diff options
| author | Jasper St. Pierre <jstpierre@mecheye.net> | 2014-04-09 20:05:02 (GMT) |
|---|---|---|
| committer | Jasper St. Pierre <jstpierre@mecheye.net> | 2014-04-09 21:54:13 (GMT) |
| commit | 912cf8ee5f13eac66c361581919a4ffea9dd06cf (patch) | |
| tree | 8bc318d6106558965f8dc74b1a381026014f7cf7 | |
| parent | 85eab49b53c4eb080b813ba59d66be2f772fa4c8 (diff) | |
| parent | 954677dcbd6ef07e7d26db2f409ec3da5c4fe2c3 (diff) | |
| download | mutter-912cf8ee5f13eac66c361581919a4ffea9dd06cf.zip mutter-912cf8ee5f13eac66c361581919a4ffea9dd06cf.tar.xz | |
Merge branch 'wayland'
This has one regression: the basic touch support added by
Carlos Garnacho in 991c85f is now partially reverted, since
we ported to Clutter events for this. We'll need to either
port his changes to Clutter, or restructure event handling
in mutter directly.
176 files changed, 23624 insertions, 31708 deletions
@@ -23,7 +23,7 @@ src/50-mutter-navigation.xml src/50-mutter-system.xml src/50-mutter-windows.xml src/mutter-wm.desktop -src/mutter.desktop +src/mutter-wayland.desktop *.o *.a *.lo @@ -46,12 +46,13 @@ POTFILES po/*.pot 50-metacity-desktop-key.xml 50-metacity-key.xml -libmutter.pc -mutter -mutter-theme-viewer -mutter.desktop +libmutter-wayland.pc +mutter-wayland +mutter-launch org.gnome.mutter.gschema.valid org.gnome.mutter.gschema.xml +org.gnome.mutter.wayland.gschema.valid +org.gnome.mutter.wayland.gschema.xml testasyncgetprop testboxes testgradient @@ -75,9 +76,15 @@ src/mutter-enum-types.[ch] src/stamp-mutter-enum-types.h src/mutter-marshal.[ch] src/stamp-mutter-marshal.h -src/meta-dbus-xrandr.[ch] +src/meta-dbus-display-config.[ch] src/meta-dbus-idle-monitor.[ch] src/mutter-plugins.pc +src/gtk-shell-protocol.c +src/gtk-shell-server-protocol.h +src/xdg-shell-protocol.c +src/xdg-shell-server-protocol.h +src/xserver-protocol.c +src/xserver-server-protocol.h doc/reference/*.args doc/reference/*.bak doc/reference/*.hierarchy @@ -95,3 +102,11 @@ doc/reference/meta-undocumented.txt doc/reference/meta-unused.txt doc/reference/meta-docs.sgml doc/reference/meta.types +gtk-doc.m4 +intltool.m4 +libtool.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 +lt~obsolete.m4 +.dirstamp diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index 9971ab0..0000000 --- a/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Havoc Pennington <hp@redhat.com> diff --git a/COMPLIANCE b/COMPLIANCE deleted file mode 100644 index b45a672..0000000 --- a/COMPLIANCE +++ /dev/null @@ -1,159 +0,0 @@ -Metacity Standards Compliance -============================= -$Id$ - -1) Introduction -2) EWMH Compliance - a. Root Window Properties - b. Root Window Messages - c. Application Window Properties - d. Window Manager Protocols -3) ICCCM Compliance - -1) Introduction ---------------- - -This document details metacity compliance with the relevent standards. -The format of this document is as follows: - -[-/+?] Hint Name/Feature Name (Version number) - Errata/Comments - -The first character indicates the level of compliance as follows: - - none - / partial - + complete - ? unknown - -The title indicates a feature or a hint in the specification, and the -version number indicates the minimum version of the specification -supported by metacity. Later versions may be supported if no -incompatible changes have been made in the specification. - -2) EWMH Compliance ------------------- - -The EWMH, or Extended Window Manager Hints is a freedesktop.org- -developed standard to support a number of conventions for -communication between the window manager and clients. It builds on -and extends the ICCCM (See Section 3). A copy of the current EWMH -standard is available at http://freedesktop.org/Standards/wm-spec/ - - a. Root Window Properties - ------------------------- - -+ _NET_SUPPORTED (1.3) - -+ _NET_CLIENT_LIST (1.3) - -+ _NET_NUMBER_OF_DESKTOPS (1.3) - -+ _NET_DESKTOP_GEOMETRY (1.3) - Metacity does not implement large desktops, so this is kept set to - the screen size. - -+ _NET_DESKTOP_VIEWPORT (1.3) - Metacity does not implement viewports, so this is a constant (0,0). - -+ _NET_CURRENT_DESKTOP (1.3) - -+ _NET_DESKTOP_NAMES (1.3) - -+ _NET_ACTIVE_WINDOW (1.3) - -+ _NET_WORKAREA (1.3) - -+ _NET_SUPPORTING_WM_CHECK (1.3) - -+ _NET_VIRTUAL_ROOTS (1.3) - Metacity does not read or set this property, but it does not use - virtual roots to implement virtual desktops, so it complies with the - specification. - -+ _NET_DESKTOP_LAYOUT (1.3) - -+ _NET_SHOWING_DESKTOP (1.3) - - b. Root Window Messages - ----------------------- - -+ _NET_CLOSE_WINDOW (1.3) - -- _NET_MOVERESIZE_WINDOW (1.3) - Metacity supports this message, but the specification is unclear on - the layout of the detail value, and as such it is #if 0'd in the code - -+ _NET_WM_MOVERESIZE (1.3) - -- _NET_RESTACK_WINDOW (1.3) - Metacity will raise or lower windows in response to this message, - but the sibling restack modes are not supported, and it is currently - #if 0'd in the code. - -+ _NET_REQUEST_FRAME_EXTENTS (1.3) - - c. Application Window Properties - -------------------------------- - -+ _NET_WM_NAME (1.3) - -+ _NET_WM_VISIBLE_NAME (1.3) - Metacity does not set this property, but metacity will never display - a name different from _NET_WM_NAME - -+ _NET_WM_ICON_NAME (1.3) - -+ _NET_WM_VISIBLE_ICON_NAME (1.3) - Metacity does not set this property, but metacity will never display - a name different from _NET_WM_NAME - -+ _NET_WM_DESKTOP (1.3) - -+ _NET_WM_WINDOW_TYPE (1.3) - -/ _NET_WM_STATE (1.3) - This property is read and updated according to the specification, - but see caveat below. - Metacity does not recognize separate vertical and horizontal - maximization states. Currently metacity will do a two-dimensional - maximization if either property is set. - See: http://bugzilla.gnome.org/show_bug.cgi?id=113601 - Metacity doesn't implement viewports so _NET_WM_STATE_STICKY is - unimplemented. - -+ _NET_WM_ALLOWED_ACTIONS (1.3) - Metacity keeps this hint up to date. The code is somewhat crufty - and should be rewritten, though it is functional. - See: http://bugzilla.gnome.org/show_bug.cgi?id=90420 - -+ _NET_WM_STRUT (1.3) - -+ _NET_WM_STRUT_PARTIAL (1.3) - -+ _NET_WM_ICON_GEOMETRY (1.3) - Metacity uses this property to draw minimize/restore animations - -+ _NET_WM_ICON (1.3) - -+ _NET_WM_PID (1.3) - -+ _NET_WM_HANDLED_ICONS (1.3) - Metacity does not read or set this property. However, metacity - never manages iconified windows, and so has no need to do so. - -+ _NET_WM_USER_TIME (1.3) - Metacity uses this property to prevent applications from stealing - focus if supported by the toolkit. - -+ _NET_FRAME_EXTENTS (1.3) - If set in response to a _NET_REQUEST_FRAME_EXTENTS message received - prior to the window being mapped, this may be an estimate. This is, - however, expressly allowed by the specification. - - d. Window Manager Protocols - --------------------------- -+ _NET_WM_PING (1.3) - -3) ICCCM Compliance -------------------- -TODO
\ No newline at end of file diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index e68822d..0000000 --- a/ChangeLog +++ /dev/null @@ -1,15414 +0,0 @@ -2009-03-16 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.26.0 release. - -2009-02-04 Neil Jagdish Patel <njpatel@gmail.com> - - * src/core/frame.c: queue resize on window undecorate - -2009-02-03 Luca Ferretti <elle.uca@libero.it> - - * src/include/all-keybindings.h: Fix description, focus the - desktop, not desktop backgroung (Closes bug #569649) - -2009-02-02 Matt Kraai <kraai@ftfbs.org> - - * src/core/schema-bindings.c: Wrap g_error calls in braces. - -2009-02-01 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.25.233. - -2009-02-01 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.144 release. - -2009-02-01 Matt Kraai <kraai@ftbfs.org> - - Set prop_hooks_table to NULL after freeing it. - - * src/core/window-props.c: - -2009-01-29 Thomas Thurman <tthurman@gnome.org> - - Window properties are looked up in a hash table rather than - by iteration over an array. Saves ~44us per window, but - also makes the code cleaner. - - * src/core/display-private.h: - * src/core/window-props.c: - -2009-01-27 Matthias Claesen <mclasen@redhat.com> - - * src/core/edge-resistance.c: some lists failed to keep track - of their contents and therefore didn't free correctly. - Closes #552303. - -2009-01-27 Matthias Claesen <mclasen@redhat.com> - - * src/core/prefs.c: Free name of old theme when new theme - is loaded. Closes #552973. - -2009-01-27 Matthias Claesen <mclasen@redhat.com> - - * src/ui/ui.c: free the result of gdk_text_property_to_utf8_list() - even when it returns no data. - -2009-01-27 Owen Taylor <otaylor@redhat.com> - - GtkStyle is specific to a particular colormap. Metacity - uses different colormaps for windows with different - visuals, so it must specialize the GtkStyle. - - Closes #568365 and #513944. - - * src/ui/frames.[ch]: Keep a GtkStyle for each MetaUIFrame, which is - obtained by calling gtk_style_attach() on the style for the - MetaFrames. When the style of the MetaFrames changes, reattach - everything. When we call gtk_style_set_background() pass in the - right style. - - * src/ui/themes.[ch]: Create a _with_style() variant of functions that - previously took the style from widget->style passed in, so we - can draw with the right style for the colormap. - -2009-01-27 Thomas Thurman <tthurman@gnome.org> - - Added a gconf key to swap the meanings of the right and - middle buttons when the modifier key is held down. - Closes #437910. Thanks to Matt Kraai for looking over - the patch. - - * src/core/display.c: - * src/core/prefs.c: - * src/include/prefs.h: - * src/metacity.schemas.in.in: - -2009-01-27 Thomas Thurman <tthurman@gnome.org> - - All the window properties are now handled using simple - window property handlers. Closes #549886. - - * src/core/window-private.h: - * src/core/window-props.c: - * src/core/window.c: - -2009-01-26 Thomas Thurman <tthurman@gnome.org> - - More of the window properties are checked using simple - window property handlers. The ones which remain don't - actually look up the new value in the ordinary way, and - so are a little trickier to merge. Added an "initial" - flag to be on the safe side that the behaviour is the - same as before (so we don't do things when a window's - first mapped that we only used to do when a property - changed). Partial fix for bug #549886. - - * src/core/window-props.c: - * src/core/window-props.h: - * src/core/window.c: - -2009-01-25 Elijah Newren <newren gmail com> - - * src/core/window.c: add support for _NET_WM_MOVERESIZE_CANCEL. - -2009-01-10 Thomas Thurman <tthurman@gnome.org> - - * src/ui/theme.[ch]: add meta_theme_draw_frame_by_name, which - is needed for the theme editor. - -2008-12-26 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.25.144. - -2008-12-26 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.89 release. - -2008-12-25 Thomas Thurman <tthurman@gnome.org> - - * src/include/all-keybindings.h: alt-F10 toggles maximisation, - alt-F5 only restores. Also rename "unmaximize" to "restore". - * src/ui/frames.c: Rename "unmaximize" to "restore". - Closes #343824. - -2008-12-25 Frederic Peters <fpeters@0d.be> - - * src/core/main.c: (main): added call to g_thread_init(), as ORBit2 - stopped doing it and Metacity is using gconf; closes #565517. - -2008-12-24 Yanko Kaneti <yaneti@declera.com> - - * src/metacity.schemas.in.in: add screenshot commands which had - mistakenly been removed; closes #564343, Launchpad bug 298463, - Red Hat bug 474635, and probably others. - -2008-12-24 Thomas Thurman <tthurman@gnome.org> - - * src/include/all-keybindings.h: fix move_to_corner_se - -2008-12-21 Colin Walters <walters@verbum.org> - - * src/core/window.c: windows which attempt to present themselves - but are offscreen end up demanding attention, unless they - are transient, when they move to the current workspace - as before. Closes #482354. - -2008-12-19 Thomas Thurman <tthurman@gnome.org> - - * src/ui/frames.c: when the user double-clicks the title bar, - end the grab op. Closes #401028. - -2008-12-16 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.25.89. - -2008-12-16 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.55 release. - -2008-12-15 Erwann Chenede <erwann.chenede@sun.com> - - * configure.in: fix build on Solaris. Closes #564123. - -2008-12-02 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.25.55. - -2008-12-02 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.34 release. - -2008-12-02 Matt Kraai <kraai@ftbfs.org> - - * src/core/iconcache.c: patches to fixes for -Wall. Closes #562939. - -2008-12-01 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.25.34. - -2008-12-01 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.21 release. - -2008-12-01 Thomas Thurman <tthurman@gnome.org> - - * configure.in: gnome-doc-tools version doesn't need to be so high. - * src/compositor/compositor-xrender.c: disable the entire file if the - compositor is disabled. - * src/core/async-getprop.[ch]: fixes for -Wall - * src/core/iconcache.c: fixes for -Wall - * src/core/testasyncgetprop.c: fixes for -Wall - * src/core/xprops.c: fixes for -Wall - -2008-11-26 Thomas Thurman <tthurman@gnome.org> - - * tools/announce-wrangler.py: linked language codes to po files - * tools/commit-wrangler.py: print revision url - -2008-11-26 Thomas Thurman <tthurman@gnome.org> - - * tools/announce-wrangler.py: renamed ini file - * tools/commit-wrangler.py: rewriting in terms of moap - -2008-11-25 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.25.21. - -2008-11-25 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.13 release. - -2008-11-26 Thomas Thurman <tthurman@gnome.org> - - * tools/announce-wrangler.py (added): script to produce announcements - -2008-11-26 Thomas Thurman <tthurman@gnome.org> - - * src/core/xprops.c: add casts (#562106) - -2008-11-25 Thomas Thurman <tthurman@gnome.org> - - * metacity.doap: change to standard description. - -2008-11-23 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.25.13. - -2008-11-23 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.8 release. - -2008-11-23 Thomas Thurman <tthurman@gnome.org> - - * po/POTFILES.in: add new bindings file - -2008-11-23 Daniel Macks <dmacks@netspace.org> - - reviewed by: Thomas Thurman - - * src/Makefile.am: reorder compiler flags so local includes come last. - Closes #562033. - -2008-11-23 Daniel Macks <dmacks@netspace.org> - - reviewed by: Thomas Thurman - - * configure.in: only accept --enable-compositor if we find we can - actually composite. Closes #560990. - -2008-11-23 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c: remove apparently spurious warnings about - operations on window "none" - -2008-11-23 Thomas Thurman <tthurman@gnome.org> - - * src/core/util.c: Set _POSIX_C_SOURCE to 200112L as it should always - have been, in an attempt to close #561962. - -2008-11-22 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Set -ansi so people stop complaining about C99. - -2008-11-22 Thomas Thurman <tthurman@gnome.org> - - * src/core/prefs.c: fix stupid infinite loop when GConf is turned off. - -2008-11-22 Thomas Thurman <tthurman@gnome.org> - - * src/core/prefs.c: fix two places where there was a warning - if GConf was turned off. - -2008-11-22 Thomas Thurman <tthurman@gnome.org> - - * src/core/all-keybindings.h: "backward", not "backwards" throughout. - -2008-11-20 Thomas Thurman <tthurman@gnome.org> - - * configure.in: turned on -Wall and -Werror in order to - trap as many problems as possible. - * src/ui/resizepopup.c: added correct #include. - * src/ui/theme-viewer.c: initialised variable. - * src/core/xprops.c: corrected cast. - * src/core/main.c: added warning if chdir() fails. - * src/core/schema-bindings.c: checking the return - result of fgets(). - -2008-11-20 Thomas Thurman <tthurman@gnome.org> - - Merged screen and window keybinding tables so that - we can use just one file for the both. Also incidentally - closes #528337. Further efficiencies of scale to come. - - * src/include/prefs.h: replace META_PREF_*_KEYBINDINGS - with META_PREF_KEYBINDINGS - * src/core/keybindings.c: replace *_bindings with key_bindings - and similar throughout; all window-based functions are now - guaranteed to receive a window so don't need to check for - themselves - (find_handler): moved so it can also be called from - rebuild_binding_table - * src/core/display-private.h: replace *_bindings with key_bindings - * src/core/prefs.c: update_*_binding becomes update_key_binding; - (change_notify): tidy up references to "enormous if statement" - since it's almost entirely gone now - * src/core/all-keybindings.h: new merged version of - screen-bindings.h and window-bindings.h. - -2008-11-16 David Trowbridge <trowbrds@gmail.com> - - This change adds support for the new _NET_WM_FULLSCREEN_MONITORS - property and client message. This allows client applications to request - that a fullscreen window cover more than one monitor. - - * src/include/boxes.h: - * src/core/boxes.c: Add meta_rectangle_union - - * src/core/window-private.h: - * src/core/window.c: - (meta_window_new_with_attrs, meta_window_free, set_net_wm_state, - meta_window_update_fullscreen_monitors, meta_window_client_message): Add - MetaWindow property to store fullscreen monitors field, update - _NET_WM_FULLSCREEN_MONITORS property on windows, and handle client - message. - - * src/core/atomnames.h: Add _NET_WM_FULLSCREEN_MONITORS atom. - - * src/core/constraints.c (setup_constraint_info): If - _NET_WM_FULLSCREEN_MONITORS is interesting, use the data stored in - MetaWindow::fullscreen_monitors to determine the fullscreen area instead - of the basic xinerama_info area. - -2008-11-11 Thomas Thurman <tthurman@gnome.org> - - Removed deprecated calls. Closes #560445. - - * src/core/delete.c: remove deprecated g_strcasecmp. - * src/include/main.h: no actual deprecated call, but - a mention of one which was out of date. - -2008-11-11 Maxim Ermilov <zaspire@rambler.ru> - - Clean up #includes according to the GNOME Goal. - Closes #560449. Patch is 122467. - - * src/core/place.c: - * src/ui/draw-workspace.h: - * src/ui/gradient.h: - * src/ui/metaaccellabel.c: - * src/ui/metaaccellabel.h: - * src/ui/preview-widget.c: - * src/ui/preview-widget.h: - * src/ui/resizepopup.c: - * src/ui/theme.c: - * src/ui/theme.h: - * src/ui/themewidget.h: - -2008-11-10 Elijah Newren <newren gmail com> - - * src/metacity.schemas.in.in: updated description of - raise_on_click: - http://bugzilla.gnome.org/show_bug.cgi?id=445447#c6 - -2008-11-08 Thomas Thurman <tthurman@gnome.org> - - * configure.in: added dependency on Zenity - * src/core/keybindings.c: remove error_on_generic_command() and - error_on_terminal_command(); rewrite error_on_command - in terms of meta_show_dialog() - * src/core/util.c: add meta_show_dialog() to call Zenity - * src/include/util.h: ditto - -2008-11-03 Olav Vitters <olav@bkor.dhs.org> - - * src/ui/theme-parser.c: Fix build by readding accidentally removed - '}'. - -2008-10-29 Thomas Thurman <tthurman@gnome.org> - - * src/ui/theme-parser.c: variable names in messages should be - double-quoted. Closes #558309. - -2008-10-28 Thomas Thurman <tthurman@gnome.org> - - * src/include/screen-bindings.h: fix accidental name change of - run_command_terminal. Closes #557943. - -2008-10-27 Thomas Thurman <tthurman@gnome.org> - - * src/core/prefs.c (titlebar_handler, handle_preference_update_enum): - Add initialisation which I missed on the previous checkin. Also - an extra comment. - -2008-10-27 Brian Cameron <brian.cameron@sun.com> - - Fix some crashes with the new GDM 2.24. Closes #558058. - - * src/ui/ui.c (meta_ui_parse_modifier): another null check - * src/core/prefs.c (titlebar_handler, button_layout_handler): - more null checks. - -2008-10-26 Thomas Thurman <tthurman@gnome.org> - - * src/core/prefs.c (mouse_button_mods_handler): Ignore values - of .../mouse_button_modifier key if the key's missing. - Closes Launchpad bug #258054, Launchpad bug #266929. - -2008-10-23 Frederic Peters <fpeters@0d.be> - - * doc/creating_themes/C/creating-metacity-themes.xml: added missing @id - on <book> top element. - -2008-10-23 Frederic Peters <fpeters@0d.be> - - * doc/creating_themes/Makefile.am: - * doc/creating_themes/C/creating_metacity_themes.xml: renamed document - to creating-metacity-themes to match other manuals usage of dashes. - -2008-10-23 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.25.8. - -2008-10-23 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.5 release. - -2008-10-23 Thomas Thurman <tthurman@gnome.org> - - * src/core/schema-bindings.c: fix stupid thinko which - caused defaults to be incorrect - * src/include/window-bindings.h: "space" needs to be - lowercase - -2008-10-23 Thomas Thurman <tthurman@gnome.org> - - Support _NET_WM_STATE_STICKY (i.e. allow third-party apps to decide - whether a window is on all workspaces). Bug found by Ka-Hing - Cheung. Closes #557536. - - * src/core/window.c (set_net_wm_state): report it - * src/core/window.c (meta_window_client_message): set sticky - if we receive it - * src/core/window-props.c: set sticky if we find it - * src/core/atomnames.h: add _NET_WM_STATE_STICKY - -2008-10-22 Thomas Thurman <tthurman@gnome.org> - - * src/core/schema-bindings.c: support builds outside tree properly. - * src/Makefile.am: ditto. - * po/POTFILES.skip: ditto. - -2008-10-22 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.25.5. - -2008-10-22 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.3 release. - -2008-10-22 Thomas Thurman <tthurman@gnome.org> - - * configure.in: bump to 2.25.3 (thought the release script - had already done this) - -2008-10-22 Thomas Thurman <tthurman@gnome.org> - - Fixes to make distcheck work again. - - * src/Makefile.am: include *-binding.h, and make the schema - building work when builddir != srcdir - * po/POTFILES.in (src/core/keybindings.): include *-binding.h - -2008-10-22 Götz Waschk <waschk@mandriva.org> - - * configure.in: add libm reference. Closes #557357. - -2008-10-22 Murray Cumming <murrayc@murrayc.com> - - * doc/creating_themes/C/creating_metacity_themes.xml: - Fixed various tags to make this validate. - Bug #557337 - -2008-10-22 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.2 release. - -2008-10-22 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.2 release. - -2008-10-22 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.2 release. - -2008-10-22 Joe Marcus Clarke <marcus@freebsd.org> - - * src/core/main.c (meta_finalize, sigterm_handler): new functions - * src/core/main.c (main): add sigterm_handler in case we receive - a SIGTERM. Closes #553980. - -2008-10-22 Matthew Martin <mtt.martin@gmail.com> - - * src/core/window.c (meta_window_set_demands_attention): minimised - windows are necessarily obscured. Closes #528927. - -2008-10-22 Thomas Thurman <tthurman@gnome.org> - - Slight transformation of the x-macros used in keybindings - to make them clearer: write handler names out in full - because the old suffix system was confusing to people - skim-reading, and switched the order of the last two - parameters so more would generally fit on a screen. - - * src/core/keybindings.c, src/core/schema-bindings.c - src/core/prefs.c: sympathy changes - * src/core/window-bindings.h, src/core/screen-bindings.h: - transformation as above - -2008-10-21 Christian Persch <chpe@gnome.org> - - * src/Makefile.am: fix build when schemas are not installed. - Closes #557335. - -2008-10-21 Tomas Frydrych <tf@linux.intel.com> - - * src/core/screen-bindings.h: Fix off-by-one error. - * src/core/window-bindings.h: Fix off-by-one error. - Closes #557201. - -2008-10-18 Thomas Thurman <tthurman@gnome.org> - - During a discussion with Rodney Dawes about making life easier - for the translators, he pointed out that the short and long - forms of almost all the keybindings say much the same thing - in different words. I believe this is an unconscionable burden - to place on translators, and have therefore merged the short - and long descriptions into the short description. The long - is now a general explanation of the format, plus possibly a - notice about reversibility. Closes #469361, and should solve - the l10n issue previously mentioned. - - * src/core/keybindings.c: reflect changes in *-bindings.h - * src/core/schema-bindings.c: reflect changes in *-bindings.h - * src/core/prefs.c: reflect changes in *-bindings.h - * src/core/window-bindings.h: Add flags field, always the same - currently, so that it's the same as screen-bindings.h. - Also, lose ONLY_BOUND_BY_DEFAULT, since we already had a - rather more elegant way to perform the same effect. - And merge the long and short descriptions. - * src/core/screen-bindings.h (, item): Merge the long and - short descriptions. - -2008-10-17 Murray Cumming <murrayc@murrayc.com> - - * configure.in: Call GNOME_DOC_INIT() so we can use the gnome-doc-utils - variables in our Makefile.am: - * doc/Makefile.am: - * doc/creating_themes/Makefile.am - * doc/creating_themes/C/creating_metacity_themes.xml: - Added this new DocBook document, converted from the HTML here - http://blogs.gnome.org/metacity/2008/05/30/themes/ - This will be installed for yelp and can be translated and hosted on - library.gnome.org. - -2008-10-15 Thomas Thurman <tthurman@gnome.org> - - Since Patrick Niklaus's checkin of 2008-08-14 dealt with windows with - no icons not using fallback icons, we don't need fallback icons. - - * src/ui/theme.h: remove fallback icons from struct. - * src/core/iconcache.c (meta_read_icons): don't look for fallbacks. - * src/*/ui.[ch] (meta_ui_get_fallback_icons): removed - * src/ui/theme-parser.c (typedef, parse_toplevel_element): don't - parse fallback specifications. - -2008-10-13 Thomas Thurman <tthurman@gnome.org> - - * po/POTFILES.in: add screen-bindings.h - -2008-10-13 Thomas Thurman <tthurman@gnome.org> - - * po/POTFILES.in: raw schemas is now .in.in - * po/LINGUAS: add Latin - -2008-10-12 Thomas Thurman <tthurman@gnome.org> - - Make the bindings in src/core/*-bindings.h generate - GConf schemas too. Note that there's an i18n issue - (documented in schema-bindings.c) which will be fixed - next checkin. - - * src/core/schema-bindings.c: major fixup to make it - ready for use as part of the actual build process. - * src/Makefile.am: added magic to make it call schema-bindings - after it builds it. - * src/core/window-bindings.h: added comments; - also, window menu was listed variously as alt-Space - and alt-Print; it should have been alt-Space. - * src/metacity.schemas.in.in: renamed from s/\.in$//, - sentinel added for the generated bindings, - warning at the top now untrue, and removed. - -2008-10-12 Thomas Thurman <tthurman@gnome.org> - - Fix annoying bug where alt-tab and friends would jump - backwards a space on initial movement. - - * src/core/screen-bindings.h: although reversed bindings - are necessarily reversible, don't set both bits in the - constant, or when we test for them we'll get confused. - -2008-10-12 Thomas Thurman <tthurman@gnome.org> - - An attempt to make life a little easier for our beloved translators; - this has the same behaviour as before, but removes over thirty - translation strings. - - * src/core/session.c (start_element_handler): all "attribute not found - on element" strings are identical - * src/ui/theme-parser.c (locate_attributes): allow attribute names to - be preceded with "!" (in the code) to show they're required. - (parse_aspect_ratio, parse_distance, parse_toplevel_element, - parse_style_element, parse_gradient_element, static, parse_border, - parse_style_set_element, parse_draw_op_element): use the new "!" - prefix for locate_attributes(), or in some cases just the identical - constant, for generating this error. - * src/ui/theme.c (check_state, meta_theme_validate): add - translator comments - * src/ui/resizepopup.c (update_size_window): add - translator comments - -2008-10-06 William Lachance <wrlach@gmail.com> - - Pass modified mouse button events down to panel windows - instead of dealing with them ourselves. Closes #554428. - - * src/core/display.c (prefs_changed_callback): don't grab mouse - buttons on panels - * src/core/window.c (meta_window_new_with_attrs): ditto - -2008-10-05 Thomas Thurman <tthurman@gnome.org> - - Second half of the switch to using x-macros for keybindings so that - we don't have lots of places with the same information which must - stay in the same order. This time it's screen bindings. - - * src/core/screen-bindings.h: New file, containing screen bindings. - * src/core/schema-bindings.c: added ability to output screen bindings. - * src/core/window-bindings.h: tiny tweak to comment - * src/core/keybindings.c: generate function prototypes using s-b.h; - several handlers modified to use ints rather than ints cast into - pointers, or renamed. - * src/include/prefs.h: generate names of bindings using s-b.h; - generate screen_handlers using s-b.h; - arguments to bindings are ints and not ints cast to pointers; - several handler functions renamed to consistent names. - * src/core/prefs.c (meta_prefs_set_num_workspaces, init_bindings): - generate screen_handlers using s-b.h; - generate screen_string_bindings using s-b.h (and add check for - null bindings in init_bindings to enable this simply). - -2008-10-05 Thomas Thurman <tthurman@gnome.org> - - * tools/ppa-magic.py: experimental tool for Launchpad upload - -2008-10-05 Thomas Thurman <tthurman@gnome.org> - - * metacity.doap: Havoc is an author; Thomas has an email address; - add a ton of release information going back to the early days, - although not right to the beginning. - -2008-09-26 Thomas Thurman <tthurman@gnome.org> - - * autogen.sh: not all versions of /bin/sh can handle this script, - so specify one. Also update the error message because we don't - use CVS these days. - -2008-09-20 Thomas Thurman <tthurman@gnome.org> - - * po/POTFILES.in: fix name of window-bindings.h - -2008-09-20 Thomas Thurman <tthurman@gnome.org> - - * po/POTFILES.in: added new files and re-sorted - -2008-09-12 Vincent Untz <vuntz@gnome.org> - - Install desktop files in both - .../share/applications and .../share/gnome/wm-properties. - Copied in from the 2.23.x branch. Closes #549479. - - * src/metacity-wm.desktop.in: new file - * src/.cvsignore: include the above - * src/Makefile.am: install the above - -2008-09-06 Thomas Thurman <tthurman@gnome.org> - - An attempt to keep all information about window bindings - in the same place. Screen bindings to come. - - * src/core/window-bindings.h: new file, list of all window bindings - * src/include/prefs.h: drop all the existing window-binding macros - - * src/core/schema-bindings.c (): output all the schema blocks that - would appear in metacity.schema for these window bindings. This - ought to become part of the build process, and hopefully will soon. - When this works it will also close #469361. - - * src/core/keybindings.c: generate handle_* prototypes using - x-macros; populate window_handlers using x-macros; rename several - functions to have consistent names; do_handle_move_to_workspace(), - handle_move_to_workspace_flip(), and handle_move_to_workspace() all - merged into handle_move_to_workspace. - - * src/core/prefs.c: generate window_bindings and window_string_bindings - using x-macros; (meta_prefs_set_compositing_manager) fix unrelated - problem with use of GConf functions when GConf was disabled. - - * src/core/core.c (meta_core_get_menu_accelerator): binding names - given as literals since this is the only place in the code they - now appear - - -2008-09-03 Thomas Thurman <tthurman@gnome.org> - - * src/metacity.desktop.in: removed invalid "Window Manager" group - at request of Matthias Clasen. - -2008-09-02 Thomas Thurman <tthurman@gnome.org> - - Desktop file moved, according to policy change. Closes #549479. - - * src/metacity.desktop.in: Don't display the desktop file - * src/Makefile.am: Desktop file goes in apps directory - -2008-09-01 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.25.2. - -2008-09-01 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.1 release. - -2008-09-01 Thomas Thurman <tthurman@gnome.org> - - * src/core/workspace.c: When a workspace's list of struts - is freed, free the struts too. Closes #549952, and #468075. - -2008-09-01 Thomas Thurman <tthurman@gnome.org> - - Add new move_to_center keybinding, requested by Khanh-Dang Nguyen - Thu Lam; closes #549979. - - * src/include/prefs.h (void): add name of new binding - * src/core/prefs.c: added pref for it - * src/core/keybindings.c (handle_move_to_center): new function - * src/metacity.schemas.in: included new binding - -2008-08-31 Thomas Thurman <tthurman@gnome.org> - - * src/core/prefs.[ch] (meta_prefs_set_compositing_manager): new - function. - * src/core/main.c (meta_parse_options): turn the compositing - manager on or off as necessary. - -2008-08-30 Thomas Thurman <tthurman@gnome.org> - - * src/core/window.c (process_property_notify): moving all - messages about properties to the top, as a start at #549886 - -2008-08-18 Thomas Thurman <tthurman@gnome.org> - - * NEWS: fix version number which broke - -2008-08-18 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release version bump to 2.25.1. - -2008-08-18 Thomas Thurman <tthurman@gnome.org> - - * configure.in: correct incorrect version number - -2008-08-18 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.25.1 release. - -2008-08-18 Thomas Thurman <tthurman@gnome.org> - - Adding doxygen headers to some files. - - * src/core/metacity-Xatomtype.h - * src/core/main.c - * src/core/screen-private.h - * src/core/window-private.h - * src/core/keybindings.h - * src/core/session.h - * src/core/workspace.h - * src/core/window-props.h () - -2008-08-18 Eric Piel <e.a.b.piel@tudelft.nl> - - * src/core/workspace.c (ensure_work_areas_validated): add a copy of - each strut in a window to the workspace's strut list, instead of - using the copy in the list (which would mean it was double-freed). - Believed to fix #468075. - -2008-08-16 Ted Percival <ted@midg3t.net> - - Ensure the user_rect is set sanely for windows that start maximized. - Prevents maximized windows from warping across the screen. - Fixes bug #504692. - - * src/core/window.c (save_user_placement): renamed version of - meta_window_save_user_rect(). - * src/core/window.c (force_save_user_placement): similar, but will - always save user_rect even if the window is maximised or fullscreen. - * src/core/window.c (meta_window_move_resize_internal): unplaced - windows have force_save_user_placement() called instead of - save_user_placement(). - -2008-08-14 Patrick Niklaus <marex@compiz-fusion.org> - - Icons for windows are taken from the desktop theme, not from - the Metacity theme or from the fallback icon that Metacity - provided. Closes #524343. - - * src/ui/ui.c: Use GtkIconTheme to load the default window icon. - Assumes the existence of an icon called "window", otherwise - falls back to "gtk-missing-image". Fixes #524343. - * src/ui/preview-widget: See above. - * src/include/common.h: Add META_DEFAULT_ICON_NAME. - * src/Makefile.am: Remove default_icon.png from inlinepixbufs.h. - * src/default_icon.png: Removed. - -2008-08-14 Akira TAGOH <akira@tagoh.org> - - * doc/man/metacity-message.1: new manual page. - * doc/man/Makefile.am: added new reference. - -2008-08-13 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-branch bump to 2.25.0. - -2008-08-04 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.23.144. - -2008-08-04 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.89 release. - -2008-07-26 Thomas Thurman <tthurman@gnome.org> - - * metacity.doap (added): DOAP file (first pass, anyway). - -2008-07-14 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.23.89. - -2008-07-14 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.55 release. - -2008-07-13 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c (event_callback): meta_display_screen_for_root() - can return NULL, so check for that. Fixes #422242. Also tidying. - -2008-07-13 Elijah Newren <newren gmail com> - - * src/core/workspace.c (meta_workspace_free): Don't attempt to - double-free struts, edges and regions if work areas have already - been invalidated at the time of freeing a workspace. - Possible fix to #361804. - -2008-07-12 Thomas Thurman <tthurman@gnome.org> - - * src/core/constraints.c (do_screen_and_xinerama_relative_constraints): - Don't allocate memory for log messages unless we're logging. - -2008-07-12 Thomas Thurman <tthurman@gnome.org> - - * src/core/group.c (meta_window_get_group): This function can now - officially return NULL. - * src/core/window.c (meta_window_same_application): Two windows can't - belong to the same application unless they both belong to some - application. (Both belonging to no application is not the same.) - -2008-06-30 Thomas Thurman <tthurman@gnome.org> - - * src/core/bell.c (meta_bell_set_audible): Fix typo that - slipped through. - -2008-06-30 Thomas Thurman <tthurman@gnome.org> - - * src/core/bell.[ch]: Move comments for non-statics from the .c to .h. - * Doxyfile: adapt better for C, and make quiet. - -2008-06-29 Thomas Thurman <tthurman@gnome.org> - - * src/ui/theme-viewer.c (main): display the theme name - in the title bar. Closes #430198. - -2008-06-29 Thomas Thurman <tthurman@gnome.org> - - Allow toggling of non-compositor effects (since there's a - non-Metacity key to do so: /desktop/gnome/interface/enable_animations). - Closes #92867. - - * src/include/prefs.h: add META_PREFS_GNOME_ANIMATIONS key and - meta_prefs_get_gnome_animations() function - * src/include/prefs.c: added meta_prefs_get_gnome_animations() - function, and made supporting changes to structs. - * src/core/effects.c (run_handler): checked whether enable_animations - is set before running an effect. - * src/core/effects.c (meta_effect_run_minimize): remove debug message. - -2008-06-29 Thomas Thurman <tthurman@gnome.org> - - * src/core/bell.c: remove meta_ prefix on all static functions. - -2008-06-29 Thomas Thurman <tthurman@gnome.org> - - * src/core/stack.c (stack_sync_to_server): lose meta prefix - since it's static. - * src/core/stack.c (meta_stack_remove, stack_do_window_deletions): - replace our own cast with glib macro designed to do the same thing - -2008-06-28 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c, src/compositor/compositor-xrender.c: add checks - for HAVE_SHAPE where appropriate. - * src/core/xprops.c: fix type error which was causing warnings. - -2008-06-28 Thomas Thurman <tthurman@gnome.org> - - Some refactoring, simplifying, and commenting of the non-composited - effects code. effects.c could still do with some polish, which will - come along later. - - * src/core/effects.h (meta_push_effect_handler): removed since it's - never used and does nothing very useful. - * src/core/effects.h (meta_pop_effect_handler): removed since its - only effect is to crash the program. - * src/core/effects.h (META_MINIMIZE_ANIMATION_LENGTH, - META_SHADE_ANIMATION_LENGTH): move to effects.c because they're used - nowhere else. - * src/core/effects.c: there were three versions of the box-zoom effect. - Remove the one which was never used, and make only the ones which - are used with certain configure settings be compiled. - * src/core/effects.h (meta_effect_end): move to effects.c, make static, - and rename to effect_free. - * src/core/effects.h (meta_effects_draw_box_animation): move to - effects.c, make static, and rename to draw_box_animation. - * src/core/effects.h (MetaEffectType): remove the values which weren't - used. - * src/core/window.c (meta_window_shade): remove commented-out code to - call effect for shading. - * src/core/effects.h (MetaEffectFinish): remove useless MetaEffect - parameter. - * src/core/window.c (finish_minimize): remove MetaEffect parameter. - -2008-06-27 Thomas Thurman <tthurman@gnome.org> - - * src/core/stack.h: Commented everything. - -2008-06-26 Thomas Thurman <tthurman@gnome.org> - - Keep the compiler from giving some warnings. - - * src/compositor/compositor-xrender.c (xrender_begin_move, - xrender_update_move, xrender_end_move, xrender_free_window): four - functions which were never called and contain no code #iffed out. - * src/tools/metacity-mag.c (grab_area_at_mouse): fixed typecast error. - -2008-06-26 Thomas Thurman <tthurman@gnome.org> - - Refactor so the long scary stack functions are less long and scary: - - * stack.c (stack_ensure_sorted): the five parts of this long function - broken out into the new functions stack_do_window_deletions, - stack_do_window_additions, stack_do_relayer, stack_do_constrain - (which was already separate: see next) and stack_do_resort. - * stack.c (constrain_stacking): renamed to stack_do_constrain. - * stack.c (stack_ignore_sorted): lose meta prefix since it's static. - -2008-06-16 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.23.55. - -2008-06-16 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.34 release. - -2008-06-16 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.34 release. - -2008-06-13 Thomas Thurman <tthurman@gnome.org> - - * src/core/window-props.c: Some commenting. - - * src/core/prefs.c: Added unified handling of integer preferences. - Re-ordered fields in existing preferences so that changing to - a union-based system will be easier in the future. - -2008-06-10 Thomas Thurman <tthurman@gnome.org> - - * test/tokentest/tokentest.c (draw_string_to_spec): doubles are - %f or %g, not %d - * test/tokentest/tokentest.ini: re-created fair copy accordingly - -2008-06-10 Thomas Thurman <tthurman@gnome.org> - - * test/tokentest: A preliminary attempt at a test for the - theme expression tokeniser. - -2008-06-05 Thomas Thurman <tthurman@gnome.org> - - * src/compositor/compositor-xrender.c (paint_root, destroy_win, - create_root_buffer, paint_windows, repair_screen, window_has_shadow, - xrender_set_active_window, paint_dock_shadows, unmap_win, restack_win, - make_shadow, resize_win, process_property_notify, free_win, - process_configure_notify, process_circulate_notify, add_damage): - defensive programming; check meta_screen_get_compositor_data() - throughout in case it returns NULL. In particular, when this - happened in a certain situation in xrender_set_active_window - this caused a segfault; refs #530702 (and LP#178953 has more data) - but this doesn't close them. - -2008-06-02 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.34 release. - -2008-06-02 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c: make sure compositor things don't get - compiled when we're not using the compositor. - -2008-06-02 Thomas Thurman <tthurman@gnome.org> - - * test/metacity-test: new test script, imported from - branch. - -2008-05-30 Thomas Thurman <tthurman@gnome.org> - - * src/core/window-props.h: fix comments (number) - -2008-05-30 Thomas Thurman <tthurman@gnome.org> - - * src/core/window-props.h: commenting - -2008-05-28 Thomas Thurman <tthurman@gnome.org> - - * src/core/prefs.c (handle_preference_update_string, - meta_prefs_remove_listener, queue_changed): Make disabling - gconf work again. Closes #530870. - -2008-05-26 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.23.34. - -2008-05-26 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.21 release. - -2008-05-26 Thomas Thurman <tthurman@gnome.org> - - * src/Makefile.am: added in two files needed for Iain's - changes earlier to work in a release tarball - -2008-05-24 Iain Holmes <iain@gnome.org> - - * src/compositor/compositor-xrender.c: Add Dropdown menu atoms so we - can add shadows to them. Fixes #517442 - Handle tooltips as well. Fixes #517524 - -2008-05-24 Iain Holmes <iain@gnome.org> - - * src/compositor/compositor.c: Check the compositor isn't NULL before - dereferencing it. Fixes #534569 - (meta_compositor_get_window_pixmap): Actually return a value - -2008-05-19 Iain Holmes <iain@gnome.org> - - * src/core/window.c: Applied patch from Ed Catmur to fix #528787 - -2008-05-19 Iain Holmes <iain@gnome.org> - - * src/include/frame.h - * src/include/display.h - * src/include/xprops.h - * src/include/compositor.h - * src/include/types.h - * src/include/window.h - * src/include/errors.h - * src/include/screen.h: New basic public API for compositor. - - * src/compositor/*: Separate the compositor out into its own separate - directory and set it up for backends. Initial XRender backend. - - * src/core/compositor.[ch]: Remove - - * src/core/frame.h - * src/core/screen.h - * src/core/display.h - * src/core/window.h: Rename to -private.h so as not to clash with the - new files in include - - * src/core/delete.c - * src/core/workspace.h - * src/core/stack.[ch] - * src/core/keybindings.[ch] - * src/core/errors.c - * src/core/effects.[ch] - * src/core/core.c - * src/core/group.h - * src/core/edge-resistance.[ch] - * src/core/window-props.[ch] - * src/core/constraints.h - * src/core/bell.[ch] - * src/core/iconcache.h - * src/core/session.[ch] - * src/core/main.c - * src/core/place.h - * src/core/xprops.c - * src/ui/tabpopup.c: Use the new -private headers - - * src/core/display.c - * src/core/frame.c - * src/core/window.c - * src/core/screen.c: Add the API functions required by the compositor - - * src/Makefile.am: Relocate the new files - -2008-05-13 Robert Escriva <me@robescriva.com> - - * src/ui/theme.h (struct): remove color_set flag - * src/ui/theme.c (meta_color_spec_render, - meta_color_spec_new_from_string): remove check of color_set flag - before rendering (we always do it now). Closes #511826. - -2008-05-12 Thomas Thurman <tthurman@gnome.org> - - * tools/xlib.py: Basic Python-based Xlib client for testing - and building upon. - -2008-05-09 Elijah Newren <newren gmail com> - - * src/ui/color.[ch]: - Remove these two unused files - -2008-05-04 Thomas Thurman <tthurman@gnome.org> - - Added curly brackets in two places to keep -pedantic happy. - - * src/core/window-props.c (meta_display_init_window_prop_hooks) - * src/core/group-props.c (meta_display_init_group_prop_hooks) - -2008-05-03 Matt Krai <mkraai@beckman.com> - - * src/core/delete.c (io_from_ping_dialog): fix type of "len" variable - (refs #526049) -2008-05-02 Thomas Thurman <tthurman@gnome.org> - - All information should live in exactly one place. This means - that the list of atoms should not be replicated anywhere. - Therefore, we include it via x-macros. Closes #530843. - - * src/core/atomnames.h: added list of atom names - * src/Makefile.am: added reference to new file - * src/core/display.h - * src/core/display.c (twice) - * src/core/screen.c: #included atomnames.h instead of having - an enormous list of atoms - * src/core/group-props.c - * src/core/window.c - * src/core/compositor.c - * src/core/window-props.c - * src/core/delete.c - * src/core/workspace.c - * src/core/stack.c - * src/core/keybindings.c - * src/core/iconcache.c - * src/core/group.c - * src/core/xprops.c: changed to new, simpler identifiers - for atoms - -2008-04-29 Chris Wang <chris.wang@sun.com> - - * src/core/window.c (meta_window_new): XGetWindowAttributes - can return an error value, and if it does its other results - are invalid! (#530485) - -2008-04-29 Thomas Thurman <tthurman@gnome.org> - - * src/ui/fixedtip.[ch]: documentation - -2008-04-27 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.23.21. - -2008-04-27 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.13 release. - -2008-04-27 Erwann Chenede <erwann.chenede@sun.com> - - * src/core/place.c (meta_window_place): re-enable cascade - code which was wrongly removed a year ago. Closes #529925. - -2008-04-22 Carlos Garnacho <carlos@imendio.com> - - * src/core/compositor.c (process_property_notify, - find_window_in_display): Propagate opacity to frame window. - -2008-04-22 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.23.13. - -2008-04-22 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.8 release. - -2008-04-22 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.21.8. - (Which was seriously belated. Sorry, folks.) - -2008-04-22 Thomas Thurman <tthurman@gnome.org> - - * src/core/effects.c: a few comments - -2008-04-10 Lucas Rocha <lucasr@gnome.org> - - * src/Makefile.am: no need to create a symlink to .desktop file in - default-session directory anymore as gnome-session will find - metacity's .desktop in its original place. - -2008-04-07 iain <iain@gnome.org> - - * src/core/compositor.c (hide_overlay_window): Hide the overlay window - (meta_compositor_unmanage_screen): Release the compositor overlay. - (#526770) - -2008-04-07 Jens Granseuer <jensgr@gmx.net> - - * src/core/session.c: (save_state), - (warn_about_lame_clients_and_finish_interact): - reorder declarations so we don't break C89 compilers. - -2008-04-06 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.5 release. - -2008-04-03 Thomas Thurman <tthurman@gnome.org> - - * src/core/prefs.c (handle_preference_update_bool): preferences - which have a null target don't get updated! (#526016) - -2008-03-29 Lucas Rocha <lucasr.at.mundo@gmail.com> - - * src/metacity.desktop.in, src/Makefile.am: make Metacity - install its desktop files in the default session directory - as required by the new gnome-session. (Closes #525051.) - -2008-03-29 Thomas Thurman <tthurman@gnome.org> - - * src/ui/preview-widget.c (meta_preview_get_clip_region): - prevent null dereference if the theme was invalid, which - caused crashes in gnome-appearance-properties. No GNOME - bug number, but I believe this is a fix for Launchpad bug - #199402 and its many duplicates. - -2008-03-28 Owen Taylor <otaylor@redhat.com> - - * src/core/window.c (meta_window_new_with_attrs): Don't - immediately unminimize an initially iconic window (#491090) - -2008-03-27 Thomas Thurman <tthurman@gnome.org> - - * src/core/session.c (regenerate_save_file, save_state, load_state): - files are saved in ~/.config/metacity/sessions and checked for there - and in ~/.metacity/sessions. Fixes #518596. - -2008-03-27 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c (meta_display_close): fix regression - where Metacity sometimes wouldn't quit when replaced - -2008-03-26 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c (event_callback): meta_display_screen_for_root - is quite capable of returning NULL. - -2008-03-25 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c (meta_display_queue_retheme_all_windows, - meta_set_syncing, meta_display_set_cursor_theme, disable_compositor, - meta_display_for_x_display, meta_display_open, meta_display_close, - meta_display_ungrab): MetaDisplay becomes a singleton. The static - variable which holds this singleton is renamed "the_display" so as - not to mask the this parameter in the methods. - - * src/core/main.c (main): - * src/core/session.c (warn_about_lame_clients_and_finish_inte, - save_state, io_from_warning_dialog): - * src/core/core.c (meta_core_increment_event_serial): - * src/core/delete.c (release_window_with_fd, search_and_destroy_window): - sympathy changes for this, and consequent simplification. - Closes #499301. - -2008-03-21 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.23.5. - -2008-03-21 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.3 release. - -2008-03-21 Thomas Thurman <tthurman@gnome.org> - - * src/ui/menu.c (activate_cb, get_workspace_name_with_accel): Workspaces - whose name is the standard name plus a non-empty string are handled - correctly in menus. Closes #453678. - -2008-03-19 Iain Holmes <iain@gnome.org> - - * src/core/compositor.c (meta_compositor_set_active_window): Handle - compositor being disabled and don't crash. - -2008-03-19 Iain Holmes <iain@gnome.org> - - * src/core/compositor.c (meta_compositor_set_active_window): Add a - screen argument. - (process_property_notify): Damage the whole screen when the background - changes. Fixes 522599 - (add_repair): Use the idle instead of the timeout. Fixes 522166 - (unmap_win): If the window is also focus window NULLify it. - - * src/core/window.c (meta_window_notify_focus): Notify when a window - has lost focus, pass in screen as well. - -2008-03-18 Iain Holmes <iain@gnome.org> - - * src/core/compositor.c (window_has_shadow): Allow shaped windows - _with frames_ to have shadows. - (meta_compositor_set_active_window): Watch for the focus of windows - and change the size of the drop shadows. - (generate_shadows): Create differently sized shadows. - (meta_compositor_get_window_pixmap): Get the xwindow correctly. - - * src/core/window.c (meta_window_notify_focus): Set the active window - in the compositor. - -2008-03-18 Marco Pesenti Gritti <mpgritti@gmail.com> - - * src/core/window.c (window_would_be_covered): newly created windows - can't be considered to be above themselves; fixes bug #519188. - -2008-03-11 Matthew Wilson <msw@gimp.org> - - * src/core/keybindings.c (meta_display_process_key_event, process_event, - find_handler, process_mouse_move_resize_grab): allow moving workspace - while moving window with modifier - * src/core/workspace.c (meta_workspace_activate_with_focus): remove the - correct window on jumping workspace while moving - -2008-03-10 Josh Lee <jleedev@gmail.com> - - * src/core/compositor.c (window_has_shadow): Don't shadow - shaped windows. - -2008-03-07 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.23.3. - -2008-03-07 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.2 release. - -2008-03-07 Thomas Thurman <tthurman@gnome.org> - - * src/core/prefs.c (mouse_button_mods_handler): remove - debug statements (*blush*) - -2008-03-06 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.23.2. - -2008-03-06 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.1 release. - -2008-03-06 Thomas Thurman <tthurman@gnome.org> - - * tools/release-wrangler.py: basic md5 printing (not used yet); - also print release announcements to stdout (eventually will - need to be emailed to release list and blogged) - -2008-03-06 Thomas Thurman <tthurman@gnome.org> - - Part three of the great prefs refactor, this time - dealing with string preferences. (This was the most - complicated part, and has been especially tested and - valground before committing. As ever, though, let us - know if you find a problem.) - - * src/core/prefs.c (MetaStringPreference): new struct. - * src/core/prefs.c (update_*): replaced with *_handler - * src/core/prefs.c (meta_prefs_init): uses new string prefs - init; uses array of gconf dirs to monitor rather than - repeating code. - * src/core/prefs.c (handle_preference_init_enum): tidying - * src/core/prefs.c (change_notify): uses new string prefs - -2008-03-04 Thomas Thurman <tthurman@gnome.org> - - * MAINTAINERS: added some spacing to see whether it - helps Pulse - -2008-03-03 Cosimo Cecchi <anarki@lilik.it> - - Add ability to vertically and horizontally maximise - using the mouse, by clicking the titlebar in various - ways. A very similar patch was received from Jason Ribero. - Thanks also go to Tony Houghton and Carlo Wood, who - both submitted patches which solved this differently. - Closes #358674. - - * src/include/common.h (MetaActionTitlebar): new values - for the new actions - * src/core/core.c (meta_core_maximize_{vertic|horizont}ally): - new functions. - * src/ui/frames.c (meta_frame_titlebar_event): handle the - new action values - * src/core/window.h: new macros (for regularity, not really - necessary) - * src/core/prefs.c (symtab_titlebar_action): new string - representations of the action values - * src/metacity.schemas.in: documentation - -2008-02-29 Andrea Del Signore <sejerpz@tin.it> - - Add support for "spacer" as a button type which adds some - empty space. Closes #509165. - - * src/ui/theme.c (meta_frame_layout_calc_geometry), - src/include/common.h (MetaButtonLayout), - src/core/prefs.c (update_button_layout, button_layout_equal), - src/metacity.schemas.in: add spacer support - -2008-02-28 Thomas Thurman <tthurman@gnome.org> - - * src/core/compositor.h: removed unnecessary #include which - should have been in Jim's patch (not sure how it slipped - through the tests!) - -2008-02-27 Jim Huang <jserv.tw@gmail.com> - - * src/core/spring-model.[ch]: deleted as no longer used - * src/Makefile.am: modified accordingly - -2008-02-27 Thomas Thurman <tthurman@gnome.org> - - Lots of tiny fixes to make sure we compile with - "gcc -ansi -Werror". - -2008-02-26 Jens Granseuer <jensgr@gmx.net> - - * src/core/constraints.c (constrain_aspect_ratio, - constrain_size_limits, constrain_size_increments): - reorder declarations so we don't break C89 compilers. - Closes #518917. - -2008-02-26 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.23.1. - -2008-02-26 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.23.0 release. - -2008-02-26 Thomas Thurman <tthurman@gnome.org> - - * tools/release-wrangler.py: ANY post-release bump is now the - most recent, not just the one that matches the current version. - Otherwise, you can't use these tools straight after a branch. - The changeset before this one was mislabelled because of this. - It has now been excised from the changelog. - -2008-02-25 Thomas Wood <thos@gnome.org> - - * src/ui/preview-widget.[ch] (meta_preview_get_clip_region): - allow users of the preview widget to get a mask for windows - in the correct shape for the current theme. - -2008-02-23 Thomas Thurman <tthurman@gnome.org> - - Refactor handling of boolean preferences. - - * src/core/prefs.c (handle_preference_init_bool, - handle_preference_update_bool): new functions. - * src/core/prefs.c (meta_prefs_init, change_notify): - use the new functions. - * src/core/prefs.c (update_*): several of these removed whose - only purpose was to receive boolean preferences. - * src/core/prefs.c (cleanup_error, get_bool): moved down to make - the flow of ideas more obvious. - * src/core/prefs.c (maybe_give_disable_workarounds_warning): new - function containing duplicated code from elsewhere. - * src/core/prefs.c (init_button_layout): only compiled when - HAVE_GCONF is not defined. Removed a compiler warning. - -2008-02-23 Thomas Thurman <tthurman@gnome.org> - - * tools/commit-wrangler.py: Print URL of changeset on success. - -2008-02-23 Thomas Thurman <tthurman@gnome.org> - - Refactored handling of enumerated preferences. - - * src/core/prefs.c (handle_preference_init_enum, - handle_preference_update_enum): new functions. - (meta_prefs_init, change_notify): use regularised - forms and remove old copy-and-pasted code. - Also many small similar functions removed which - only existed to deal with each kind of enum. - Also some amount of correction of which parts were - and weren't inside "#ifdef HAVE_GCONF" blocks. - - -2008-02-21 Mikkel Kamstrup Erlandsen <mikkel.kamstrup@gmail.com> - - * src/core/constraints.c: Respect requested position on - _NET_MOVERESIZE_WINDOW. Closes #448183. - -2008-02-18 Matthias Clasen <mclasen@redhat.com> - - * src/core/window.h: Make skip-taskbar windows appear in the - Ctrl-Alt-Tab list. Closes #106249. - -2008-02-18 Thomas Thurman <tthurman@gnome.org> - - * configure.in: if we have libSM and its headers, - that means we did find it, not that we didn't. - Closes #328210. - -2008-02-18 Thomas Thurman <tthurman@gnome.org> - - * src/core/window.c (warp_grab_pointer): When - resizing a window with the keyboard, stay one - pixels from the edges so that the cursor remains - resting on a window edge even if we escape, - whatever side it was on. Closes #436257. - -2008-02-17 Thomas Thurman <tthurman@gnome.org> - - * tools/commit-wrangler.py: added new script to manage commits - -2008-02-17 Jim Huang <jserv.tw@gmail.com> - - * src/core/prefs.c (update_binding): Allow compilation - when gconf mode is disabled. Closes #515019. - -2008-02-14 Jim Huang <jserv.tw@gmail.com> - - * src/core/display.c, src/core/util.c: fixups to allow - compilation in non-verbose mode. Closes #515152. - -2008-02-12 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Correct help for verbose option name. - -2008-02-12 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-branch bump to 2.23.0. - -2008-02-12 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.21.21. - -2008-02-11 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.21.13 release. - -2008-02-04 Thomas Thurman <tthurman@gnome.org> - - * src/core/compositor.c: only use compositor version if - we have a compositor. Closes #514453. - -2008-02-04 Thomas Thurman <tthurman@gnome.org> - - * configure.in, src/ui/ui.c: remove workaround for a problem - in GTK 1.3.9(!) which was causing problems. Closes #513737. - -2008-01-28 Michael Meeks <michael.meeks@novell.com> - - * src/core/display.c (meta_display_open), - * src/core/compositor.c: fetch & use composite - version, for remote screens that don't match the - compile system's version. - (meta_compositor_manage_screen): bin erroneous FIXME. - (add_win): remove common warning churn for (very) - transient windows - -2008-02-03 Thomas Thurman <tthurman@gnome.org> - - * tools/patch-wrangler.py: another program I use for maintenance - which other people might find useful and which should probably - be in svn. Also not very polished. - -2008-02-03 Thomas Thurman <tthurman@gnome.org> - - * test/tokentest/tokentest.c, test/tokentest/tokentest.ini: added - new files for a regression test on the tokeniser. (They aren't very - polished at the moment and aren't included in the autotools build.) - -2008-02-03 Thomas Thurman <tthurman@gnome.org> - - * configure.in: Post-release bump to 2.21.13. - -2008-02-03 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.21.8 release. - -2008-02-03 Thomas Thurman <tthurman@gnome.org> - - * tools/release-wrangler.py: Fix quoting error and added some - more error checking. - -2008-02-03 Thomas Thurman <tthurman@gnome.org> - - * tools/release-wrangler.py: basic release script; needs work, - but probably good enough for the current unstable release - -2008-02-02 Thomas Thurman <tthurman@gnome.org> - - * src/Makefile.am: core.h is in include, not core. (Last one, I - promise.) - -2008-02-02 Thomas Thurman <tthurman@gnome.org> - - * src/Makefile.am: main.h is in include, not core. - -2008-02-02 Thomas Thurman <tthurman@gnome.org> - - * src/Makefile.am: draw-workspace.h is in ui, not core. - -2008-02-01 Alex R.M. Turner <armtuk@gmail.com> - - * src/core/display.c (meta_get_tab_entry_list): Have the list also pull - windows that are in other workspaces that have the - wm_state_needs_attention flag set - * src/core/window.c (meta_window_set_demands_attention): Make windows that - are on other workspaces that demand attention that aren't obscured - count as being obscured - Bug #333548. - -2008-01-28 Christian Persch <chpe@gnome.org> - - * src/core/display.c (convert_property): - * src/core/screen.c (meta_screen_calc_workspace_layout): - * src/core/xprops.c (meta_prop_get_values): - Use G_STRFUNC instead of the deprecated G_GNUC_FUNCTION. - Bug #512561. - -2008-01-21 Thomas Thurman <tthurman@gnome.org> - - * src/ui/theme.[ch]: more commenting. - -2008-01-18 Thomas Thurman <tthurman@gnome.org> - - * src/ui/theme.[ch]: some more commenting. - -2008-01-16 Thomas Thurman <tthurman@gnome.org> - - * src/core/bell.c: Correct comment. - * src/core/main.c: Correct comment. - * src/ui/theme.c: Much commenting; #ifdeffed-out - debug code removed. - * src/ui/theme.h: Much commenting. - -2008-01-13 Thomas Thurman <tthurman@gnome.org> - - * src/core/bell.c: Commenting. - * src/core/main.c: Commenting, and fixing existing comments. - -2008-01-12 Thomas Thurman <tthurman@gnome.org> - - * src/core/main.c: Refactor repeated lines in main() to - iterate instead. - -2008-01-12 Thomas Thurman <tthurman@gnome.org> - - * src/core/main.[ch] (meta_get_main_loop): removed as it - was never used. - * src/core/main.c: lots of comments. - * src/core/main.c (version): copyright year is 2008. - * src/core/c-screen.[ch], src/core/c-window.[ch]: removed - files from Søren's compositor which were removed by the - merge with Iain's compositor but reintroduced by the split - to separate subdirectories. - * src/core/display.c: fix comments. - -2008-01-12 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c: reinstated missing first character! - * Doxyfile: correct reordering of blank fields. - -2008-01-12 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c: change comments from /*! to /** because the - other way makes doxygen think they are Qt comments, which messes - up brief descriptions. - * Doxyfile: check in so other people can generate documentation - too. - -2008-01-07 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c: further commenting (trying to keep comment - addings down to once a day at most so you don't all get spammed - too much). - -2008-01-07 Thomas Thurman <tthurman@gnome.org> - - * src/core/main.c (main): g_free is a no-op on nulls; there is no - need to test. - -2008-01-06 Thomas Thurman <tthurman@gnome.org> - - * src/core/display.c: Function commenting marathon; more to come. - -2008-01-02 Thomas Thurman <tthurman@gnome.org> - - * src/core/xprops.c (meta_prop_get_cardinal), src/core/compositor.c - (timeout_debug): Two really minor coding standards layout tweaks. - -2007-12-27 Iain Holmes <iain@gnome.org> - - * src/core/compositor.c: Don't do anything in - meta_compositor_free_window, it doesn't seem to be needed and breaks - things very badly. http://bugzilla.gnome.org/show_bug.cgi?id=504876 - -2007-12-27 Iain Holmes <iain@gnome.org> - - * src/core/compositor.c: When a window is mapped, don't set damaged to - TRUE. Fixes a bug when redrawing shadows. - -2007-12-25 Iain Holmes <iain@gnome.org> - - * src/core/compositor.c: USe the compositor overlay window instead of - the root window. - -2007-12-21 Paolo Borelli <pborelli@katamail.com> - - * src/core/core.c (meta_invalidate_default_icons): do not leak list. - - * src/core/edge-resistance.c - (meta_display_compute_resistance_and_snapping_edges): ditto. - - * src/core/workspace.c (meta_workspace_index): small cleanup in list - handling. - -2007-12-19 Havoc Pennington <hp@redhat.com> - - * src/core/display.c (meta_display_open): fix a third warning - about %d and long int - - * src/core/delete.c (io_from_ping_dialog): fix another warning - about long int to %d - - * src/core/compositor.c (meta_compositor_new): fix a warning about - long int to %d - - * src/core/iconcache.c (meta_read_icons): use - meta_ui_get_fallback_icons() instead of incorrectly including theme.h - - * src/ui/ui.c (meta_ui_get_fallback_icons): new function - -2007-12-19 Havoc Pennington <hp@redhat.com> - - * src/ui, src/core, src/include: sort source files into these - directories according to which part of the WM they are supposed to - be in. In an eventual plan, we should also create - src/compositor/render, src/compositor/fallback and move some of - the compositor stuff into that. - - * autogen.sh: require a newer automake, so we don't have to use - a recursive build - - * src/ui/tabpopup.c: put in a hack to make the build temporarily - work, want to commit the large rearrangement before fixing this - not to include workspace.h or frame.h - - * src/core/iconcache.c (meta_read_icons): temporarily break this - to get the build to work, want to commit the large rearrangement - before fixing this file not to include theme.h - -2007-12-19 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: Post-release bump to 2.21.8. - -2007-12-19 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.21.5 release. - -2007-12-19 Thomas Thurman <tthurman@gnome.org> - - * configure.in: print "Subversion" and not "CVS". - -2007-12-18 Thomas Thurman <tthurman@gnome.org> - - * configure.in: compositor enabled by default. - -2007-12-18 Iain Holmes <iain@gnome.org> - - * configure.in, src/theme.c, src/display.c, - src/theme.h, src/display.h, src/theme-parser.c, - src/compositor.c, src/c-screen.c, src/compositor.h, - src/c-screen.h, src/ui.c, src/screen.c, src/ui.h, - src/screen.h, src/c-window.c, src/c-window.h, - src/theme-viewer.c, src/Makefile.am: Merge compositor branch. - -2007-12-14 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: Post-release bump to 2.21.5. - -2007-12-14 Thomas Thurman <tthurman@gnome.org> - - * NEWS: 2.21.3 release. - -2007-12-11 Thomas Thurman <tthurman@gnome.org> - - * src/theme-parser.c: remove dead code; closes #501365. - -2007-12-08 Thomas Thurman <tthurman@gnome.org> - - * src/metacity.schemas.in: rewrite long description of - /schemas/apps/metacity/general/focus_new_windows because we - love the translators really. Closes #474889. - -2007-12-08 Matthias Clasen <mclasen@redhat.com> - - * src/menu.c (meta_window_menu_new): check for null before adding - menu; closes #496054. - -2007-12-08 Thomas Thurman <tthurman@gnome.org> - - * src/keybindings.c (meta_display_process_key_event): Recur if the - keypress ended a grab, so it can be processed in its own right. - Closes #112560. - -2007-12-08 Martin Meyer <elreydetodo@gmail.com> - - * src/theme-parser.c (parse_draw_op_element): Fix - typo where wrong variable was checked (reported by - Kjartan Maraas). Closes #501362. - -2007-11-19 Lucas Rocha <lucasr@gnome.org> - - * src/main.c (main): try to get the session client ID from - DESKTOP_AUTOSTART_ID environment variable in case the --sm-client-id - is not used. Closes #498033. - -2007-11-17 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: Post-release bump to 2.21.3. - -2007-11-17 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.21.2 release. - -2007-11-17 Benjamin Gramlich <benjamin.gramlich@gmail.com> - - * src/theme-parser.c (meta_theme_load): make our theme - search compliant to the XDG Base Directory Specification. - Closes #480026. - -2007-11-15 Thomas Thurman <thomas@thurman.org.uk> - - * src/api.[ch]: remove almost-unused files. - * src/colors.[ch]: move the used parts of api.[ch] in here. - Closes #496947. - -2007-11-13 Peter Bloomfield <pbloomfield@bellsouth.net> - - * src/window.c: (meta_window_save_user_rect): new helper, saves - only unmaximized dimensions, and not when fullscreen. - (meta_window_move_resize_internal, - meta_window_move_resize_request): use it. (#461927) - -2007-11-11 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: Post-release bump to 2.21.2. - -2007-11-11 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.21.1 release. - -2007-11-11 Thomas Thurman <thomas@thurman.org.uk> - - * src/window.c (meta_window_show): adjust expression which decides - whether new windows should not go on top, so that restacking happens - only the first time a window is mapped. Thanks to Olav Vitters for - pointing out the problem. Re-fixes #486445. - -2007-11-11 Alex R.M. Turner <armtuk@gmail.com> - - * src/tabpopup.c (tab_entry_new, meta_ui_tab_popup_new): Instruct the - GtkLabel in the tabpopup to ellipsize text that is too big. Set the - maximum window width of the tabpopup to screen_width/4, which seems a - sensible size for the popup. - -2007-11-09 Elijah Newren <newren gmail com> - - * src/window.c (meta_window_new_with_attrs): If a window is - launched without any kind of launch timestamp, grab the current - time and stash it away. When transients of that window are also - launched without a timestamp, we can use the stashed timestamp - from the parent. Fixes #488468. - -2007-11-07 Federico Mena Quintero <federico@novell.com> - - * src/window-props.c (reload_net_wm_user_time_window): Fix typo; - the arguments to meta_window_reload_property_from_xwindow() were - reversed. This is why the wm_user_time wasn't getting initialized - properly from the _NET_WM_USER_TIME_WINDOW. Fixes part of - http://bugzilla.gnome.org/show_bug.cgi?id=488468 - -2007-11-06 Peter Bloomfield <pbloomfield@bellsouth.net> - - * src/window.c (meta_window_move_resize_internal): save - unmaximized part of client root coords. (#461927) - -2007-11-06 Peter Bloomfield <pbloomfield@bellsouth.net> - - * src/window.c (meta_window_move_resize_internal): do not save - client root coords while window is maximized. (#461927) - -2007-10-30 iain Holmes <iain@gnome.org> - - * src/main.c (meta_parse_options): Add --sync option - (main): Check if the --sync option was passed on command line. - -2007-10-28 Jans Granseuer <jensgr@gmx.net> - - * src/preview-widget.c (meta_preview_finalize): Free title of - preview when the preview is destroyed. Closes #469682. - -2007-10-27 Alex R.M. Turner <armtuk@gmail.com> - - * src/tabpopup.c (tab_entry_new): Truncate the string to - max_char_per_title before adding bold tags and fix general flow of - function. - -2007-10-16 Thomas Thurman <thomas@thurman.org.uk> - - * src/window.c (window_would_be_covered): new function. - * src/window.c (meta_window_show): rewrite assertion not - to put window on top in terms of window_would_be_covered(); - remove assertion because it's no longer valid; explicitly - don't focus windows that shouldn't be focussed; closes #486445. - -2007-10-14 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: Post-branch bump to 2.21.1. - -2007-10-03 Kjartan Maraas <kmaraas@gnome.org> - - * configure.in: Remove circular dep metacity<->gnomecc. - -2007-09-15 Elijah Newren <newren gmail com> - - * configure.in: post-release version bump to 2.20.1 - -2007-09-15 Elijah Newren <newren gmail com> - - * configure.in: - * NEWS: - 2.20.0 release - -2007-09-15 Elijah Newren <newren gmail com> - - * src/session.c (warn_about_lame_clients_and_finish_interact): - Patch from Alexey Rusakov to prevent a crash on logout with - metacity subsequently not being restored in future sessions. - Fixes #433253. - -2007-09-01 Elijah Newren <newren gmail com> - - * HACKING: update; cvs->svn & mention GConf needed - * MAINTAINERS: Make it match idiotic format requirements (I love - you Olav!) - -2007-08-07 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.19.89. - -2007-08-07 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.19.55 release. - -2007-08-06 Thomas Thurman <thomas@thurman.org.uk> - - If KEY_AUTO_RAISE_DELAY is undefined or non-integer, it is not treated - as zero. - - * src/prefs.c (meta_prefs_init): check type of key, and behave sensibly - if it's unexpected. - * src/prefs.c (find_and_update_list_binding): remove old comment. - -2007-08-03 Frederic Crozat <fcrozat@mandriva.com> - - * src/delete.c: Fix mangled window title in "Force Quit" - dialog when using non-UTF8 locale. Close #462734. - -2007-08-02 Thomas Thurman <thomas@thurman.org.uk> - - Move "close" to bottom of window menu; allow workspace list to appear - at any position in the menu. Closes #104026. - - * src/menu.c (MetaMenuItemType): added new MENU_ITEM_WORKSPACE_LIST - item. - * src/menu.c (menuitems): reordered "close", added a workspace list. - * src/menu.c (menu_item_new): return null for workspace lists. - * src/menu.c (meta_window_menu_new): handle workspace lists. - -2007-07-31 Thomas Thurman <thomas@thurman.org.uk> - - * src/window.c (meta_window_show_menu): windows which are - always on top have the "stick" menu option insensitive. (#460997). - -2007-07-23 Thomas Thurman <thomas@thurman.org.uk> - - * src/window.h (MetaWindow): Put all bitfields together to - help with optimisation. Closes #450271 (for real this time). - -2007-07-23 Matthias Clasen <mclasen@redhat.com> - - * configure.in: - * src/Makefile.am: Use the correct directory when - installing keybindings. (#454055) - -2007-07-22 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.19.55. - -2007-07-22 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.19.34 release. - -2007-07-22 Rob Bradford <rob@robster.org.uk> - - Fix a bug where the window can be focused without being raised - if the maximize is aborted. Fixes #459027. - - * src/frames.c (meta_frames_button_press_event, - meta_frames_button_release_event): When maximising only focus - the window once the button press is released. - -2007-07-22 Cosimo Cecchi <anarki@lilik.it> - - Unset fullscreen is an allowed action where relevant. Fixes #449427. - - * src/window.c (set_allowed_actions_hint): Separate FULLSCREEN action - from RESIZE action. - -2007-07-22 Yair Hershkovitz <yairhr@gmail.com> - - Reverse window buttons and align them to the left for RTL locales. - Fixed #92212. - - * src/prefs.c (button_layout, init_button_layout, update_button_layout): - Support reversing and left-aligning of buttons for both Gconf and - NO-Gconf modes. - * src/main.c (main): Call meta_ui_init() before meta_prefs_init(). - meta_prefs_init() check for RTL locales which is initialized in - meta_ui_init(). - * src/theme.c (meta_frame_layout_calc_geometry): Fixed access to - button_layout to stop iterating when getting to a - META_BUTTON_FUNCTION_LAST value. - -2007-06-23 Thomas Thurman <thomas@thurman.org.uk> - - * src/window.c (MetaWindow): Put all bitfields together to - help with optimisation. Closes #450271. - -2007-06-18 Thomas Thurman <thomas@thurman.org.uk> - - * src/main.c (version): Update copyright year because it was - five years out of date. - -2007-06-18 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.19.34. - -2007-06-18 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.19.21 release. - -2007-06-18 Thomas Thurman <thomas@thurman.org.uk> - - * src/place.c (find_first_fit, meta_window_place): Only open new - windows on the current xinerama. Closes #145503, for now. - -2007-06-17 Thomas Thurman <thomas@thurman.org.uk> - - * src/screen.[ch] (meta_screen_apply_startup_properties): return a - boolean instead a void, to show whether startup properties were - applied. Also some commenting. - * src/window-props.c: (reload_net_startup_id): Only activate the - window if the startup_id was actually changed. Closes #400167. - -2007-06-16 Damien Carbery <damien.carbery@sun.com> - - * effects.h: MetaCloseEffect and MetaFocusEffect, which were empty - structs, #ifdeffed out because they broke the build on Solaris. - Closes #397296. - -2007-06-16 Damien Carbery <damien.carbery@sun.com> - - * window.h: make prototype of meta_window_unqueue match - implementation. Closes #446535. - -2007-06-10 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.19.21. - -2007-06-10 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.19.13 release. - -2007-06-10 Thomas Thurman <thomas@thurman.org.uk> - - Refactor thrice-duplicated queue code in window.c. Closes #376760. - - * src/window.c (meta_window_queue, meta_window_unqueue): - New functiortl.patchns. - * src/window.[ch] (meta_window_unqueue_*, meta_window_queue_*): - Removed functions. - * src/window.c (meta_window_new_with_attrs, meta_window_free, - meta_window_flush_calc_showing, queue_calc_showing_func, - meta_window_minimize, meta_window_unminimize, meta_window_maximize, - meta_window_make_fullscreen, meta_window_shade, - meta_window_unshade, meta_window_move_resize_internal, - window_stick_impl, window_unstick_impl, - meta_window_client_message, process_property_notify): Modified to - use new queueing functions. - * src/window.c (idle_move_resize, idle_update_icon, - idle_calc_showing): update to receive queue number from pointer. - * src/window.h (MetaQueueType): new enum. - * src/window.h (MetaWindow): *_queued replaced with is_in_queue - bitfield. - * src/core.c (meta_core_queue_frame_resize): - * src/display.c (event_callback, - meta_display_queue_retheme_all_windows): Using new queueing functions. - * src/frame.c (meta_window_destroy_frame): Using new queueing functions. - * src/screen.c (queue_resize, meta_screen_resize_func, - queue_windows_showing): Using new queueing functions. - * src/window-props.c (reload_mwm_hints, reload_wm_hints, - reload_transient_for): Using new queueing functions. - * src/workspace.c (meta_workspace_add_window, - meta_workspace_remove_window, meta_workspace_queue_calc_showing, - meta_workspace_invalidate_work_area): Using new queueing functions. - -2007-06-09 Thomas Thurman <thomas@thurman.org.uk> - - * src/50-metacity-key.xml.in: added switch_group; closes #444879. - -2007-06-08 Elijah Newren <newren gmail com> - - * src/metacity.schemas.in: - Update the raise_on_click description to try to prevent misuses, - to appropriately warn users, and to stop wasting the time of - application developers. #445447, #389923 - -2007-06-06 Thomas Thurman <thomas@thurman.org.uk> - - * frames.c, core.[ch]: changed all tabs to spaces. - * core.[ch] (meta_core_get_client_size, meta_core_window_has_frame, - meta_core_titlebar_is_onscreen, meta_core_get_client_xwindow, - meta_core_get_frame_flags, meta_core_get_frame_type, - meta_core_get_mini_icon, meta_core_get_icon, meta_core_get_position, - meta_core_get_size, meta_core_get_frame_workspace, - meta_core_get_frame_extents, meta_core_get_screen_size): Removed - and replaced with meta_core_get(). - * core.[ch] (meta_core_get): New function. - * core.h (MetaCoreGetType): New enum. - * frames.c (meta_frames_ensure_layout, meta_frames_calc_geometry, - meta_frames_get_geometry, meta_frames_apply_shapes, - meta_frame_titlebar_event, meta_frames_button_press_event, - populate_cache, clip_to_screen, meta_frames_paint_to_drawable, - meta_frames_set_window_background, get_control): Replace use of - removed functions in ui.c with meta_core_get(). - - All this should make things a little faster. Closes #377495. - -2007-06-04 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: Added translators' names from 2.19.8 (sorry, folks: - I forgot to save NEWS with their names in it before shipping.) - -2007-06-04 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.19.13. - -2007-06-04 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.19.8 release. - -2007-06-04 Thomas Thurman <thomas@thurman.org.uk> - - * src/metaaccellabel.c (meta_accel_label_expose_event): fix - label layout for RTL languages. Closes #433400. - -2007-06-03 Thomas Thurman <thomas@thurman.org.uk> - - * src/frames.c (meta_frames_ensure_layout): Pango layout for - titlebars should take LTR/RTL-ness from the underlying widget - and not from sniffing the content. Closes #438944. - -2007-05-25 Yair Hershkovitz <yairhr@yahoo.com> - - * src/workspace.c (meta_workspace_get_neighbor): Add support - for RTL languages so that alt-tab, etc., go the other way. - * src/keybindings.c (handle_activate_menu): In RTL locales, - pop up the menu on the right-hand side when the menu keystroke - is pressed. - * src/fixedtip.c (meta_fixed_tip_show): right-justify tooltips - in RTL locales. - * src/menu.c (popup_position_func): popup menus in RTL locales - are flush with the right-hand side of the window where possible. - * src/frames.c (show_tip_now, meta_frames_button_press_event): - tooltips are aligned with the right-hand side of buttons in - RTL locales. - * src/ui.[ch] (meta_ui_get_direction, enum MetaUIDirection): - New content. - * src/window.c (meta_window_show_menu): "move left" appears above - "move right" in the window menu for LTR locales, and vice versa - for RTL locales. - - This is all to close bug #387893. - -2007-04-24 Linus Torvalds <torvalds@woody.linux-foundation.org> - - * src/prefs.[ch] (init_action_meta_prefs, meta_prefs_init, - action_change_titlebar, change_notify, update_action_titlebar, - meta_preference_to_string): Add code to configure what happens - when the titlebar is right or middle clicked as well as - double clicked. - -2007-04-23 Elijah Newren <newren gmail com> - - * configure.in: post-release bump to 2.19.8. - -2007-04-23 Elijah Newren <newren gmail com> - - * NEWS: 2.19.5 release. - -2007-04-23 Elijah Newren <newren gmail com> - - Fix some uninitialized memory usage errors. #427385 - - * src/frame.c (meta_window_ensure_frame): - * src/frames.c (meta_frames_manage_window): - Do not try to set the window background in - meta_frames_manage_window() since the frame window is not yet - created and not yet registered with the corresponding MetaWindow. - Do it inside meta_window_ensure_frame() instead. - -2007-04-17 Elijah Newren <newren gmail com> - - Fix some fallout from #426519; update user_rect for all position - changes prior to the window being marked as placed. Prevents - emacs in particular from flickering on start and always being - shoved to the upper-left corner. - - * src/window.c (meta_window_move_resize_internal): - Record position in user_rect if the window is not yet marked as - placed too - - * src/window.c (struct MetaWindow, meta_window_new_with_attrs, - meta_window_move_resize_internal): - Remove window->user_has_move_resized; it's not needed or used - anymore. - - * src/window.[ch] (meta_window_get_user_position): - Remove this function as it is no longer needed or used. - -2007-04-16 Elijah Newren <newren gmail com> - - Prevent metacity from "forgetting" which machine a window is on. - #418552 - - * src/window.c (meta_window_new_with_attrs): reorder the property - loading so that we know the wm_client_machine when we load the - name of the window and can modify the window name accordingly. - -2007-04-16 Elijah Newren <newren gmail com> - - * configure.in: post-release bump to 2.19.5. - -2007-04-16 Elijah Newren <newren gmail com> - - * NEWS: 2.19.3 release. - -2007-04-15 Elijah Newren <newren gmail com> - - Preserve stacking order across restarts. - - * src/display.c (meta_display_unmanage_windows_for_screen): - unmap windows in stacking order so that stacking is preserved upon - shutdown - - * src/display.[ch] (meta_display_stack_cmp): - * src/session.c (stack_cmp, save_state): - rename stack_cmp() -> meta_display_stack_cmp() and move it to a - different function so that it can be used in both - session.c:save_state() and - meta_display_unmanage_windows_for_screen() - -2007-04-15 Elijah Newren <newren gmail com> - - Remove incorrect usage of window.h from menu.c. See #426791 & - #382962. - - * src/menu.c (enum MetaMenuItemType, variable menuitems, - meta_menu_item_new): - cleanup: add a MENU_ITEM_RADIOBUTTON for the sticky stuff - - * src/menu.c (variable menuitems): - * src/core.c (meta_core_get_menu_accelerator): - * src/window.c (menu_callback, meta_window_show_menu): - * src/common.h (enum MetaMenuOp): - reinstate META_MENU_OP_UNABOVE - - * src/menu.c (meta_window_menu_new): - remove hacks (using inappropriate data) for STICK/UNSTICK/ABOVE - and clean it up while just setting STICK/UNSTICK activeness as - necessary - - * src/menu.[ch] (meta_window_menu_new): - * src/ui.[ch] (meta_ui_window_menu_new): - make the active_workspace parameter an unsigned long - -2007-04-15 Bruno Boaventura <brunobol@gnome.org> - - * src/menu.c (meta_window_menu_new): don't show the current - workspace as a possible workspace to switch to. Fixes #426791. - -2007-04-12 Elijah Newren <newren gmail com> - - * src/place.c (meta_window_place): do not auto-maximize windows - larger than the workarea in only a single direction. Fixes - #419810. - -2007-04-11 Elijah Newren <newren gmail com> - - Make sure apps have correct info about their coordinates, even on - unmap. Fixes temporary hang with libXt (XtVaSetValues setting x & - y coordinates). #399552. - - * src/frame.c (meta_window_destroy_frame): Add a comment noting - that the current choice causes the need for a ConfigureNotify - event - - * src/window.c (meta_window_free): Send a configure notify event - due to our XReparentWindow coordinate choices on withdrawal, - (unmaximize_window_before_freeing): no need to send a configure - notify from here since it is always done in meta_window_free new, - (send_configure_notify): have to special case the coordinates used - when withdrawing the window - -2007-04-11 Thomas Thurman <thomas@thurman.org.uk> - - Workaround for a gdk bug which dies with BadAlloc if you try - to allocate an insanely huge rectangle for an insanely huge - window. Fixes #399529. - -2007-04-11 Elijah Newren <newren gmail com> - - Advertise support of Above and Below operations (assuming the - proposed EWMH additions of _NET_WM_ACTION_(ABOVE|BELOW) will be - accepted, otherwise these changes will have to be modified). Part - of #115247. - - * src/display.[ch] (meta_display_open, struct MetaDisplay): - * src/screen.c (set_wm_check_hint): - Add support for _NET_WM_ACTION_ABOVE and _NET_WM_ACTION_BELOW - - * src/window.c (set_allowed_actions_hints): - add active_above and action_below - -2007-04-10 Elijah Newren <newren gmail com> - - * src/window.c (recalc_window_features): make sure to set - _NET_WM_ALLOWED_ACTIONS so that libwnck menus don't have sensitive - but ineffective menu items. The "On Top" item is now buggy, but - due to the fact that _NET_WM_ACTION_ABOVE is not yet defined in - the EWMH. Fixes #115247. - -2007-04-09 Elijah Newren <newren gmail com> - - Add support for _NET_MOVERESIZE_WINDOW. Based on patch from - Magnus Therning. #344521. - - * src/display.c (handle_net_moveresize_window, event_callback): - Remove handle_net_moveresize_window() and the call to it; this - code was highly buggy, though to be fair it was never tested and - had simply been put into the code in commented out form. - - * src/screen.c (set_supported_hint): - add atom_net_moveresize_window - - * src/window.[ch]: - (meta_window_configure_request, meta_window_move_resize_request): - Split out the moving/resize part of the configure request and put - it into meta_window_move_resize_request - - (meta_window_client_message): - check for NET_MOVERESIZE_WINDOW messages and call - meta_window_move_resize_request() with the appropriate parameters - to handle them - - (meta_window_move_resize_internal): - fix some of the big comment at this function -- it wasn't quite - right, use the passed in gravity instead of - window->size_hints.win_gravity when calling adjust_for_gravity() - to make sure the correct adjustments are used. - - (meta_window_get_gravity_position, - meta_window_get_geometry, meta_window_move_resize_request): - add a gravity parameter to meta_window_get_gravity_position and - have it use that gravity instead of window->size_hints.win_gravity - -2007-04-09 Elijah Newren <newren gmail com> - - * configure.in: post-release bump to 2.19.3. - -2007-04-09 Elijah Newren <newren gmail com> - - * NEWS: 2.19.2 release. - -2007-04-08 Elijah Newren <newren gmail com> - - Remove grab_start_serial, which we expect to be an ancient attempt - to workaround sloppy/mouse focus bugs that have since been - correctly fixed. May fix some race conditions. May cause nasty - bugs in sloppy/mouse focus modes. We'll find out soon enough... - See #304430. - - * src/display.c (event_callback): - remove event->xany.serial >= display->grab_start_serial in several - event callback handlers - - * src/display.[ch] (struct _MetaDisplay, meta_display_begin_grab_op): - * src/keybindings.c (do_choose_window, handle_workspace_switch): - * src/frames.c (meta_frames_button_press_event): - * src/core.[ch] (meta_core_begin_grab_op): - * src/window.c (meta_window_client_message, meta_window_begin_grab_op): - don't require an event_serial to be passed to - meta_display_begin_grab_op () and don't record it anymore. - - * src/ui.c (struct _EventFunc, filter_func, - meta_ui_get_last_event_serial) - * src/core.h (meta_ui_get_last_event_serial): - remove meta_ui_get_last_event_serial() function (don't ask me why - it was declared in core.h) and the last_even_serial field of - _EventFunc - -2007-04-08 Elijah Newren <newren gmail com> - - Fix move/resize events in relation to combinations of - ConfigureRequest and WM_NORMAL_HINTS change notifications (plus a - few code cleanups). Fixes #426519. - - * src/window.c (meta_window_move_resize_now): - move to the user_rect position, not some weird combination of rect - and user_rect - - * src/window.c (meta_window_configure_request): - set user_rect in response to ConfigureRequest events (after the - ConfigureRequest values have been constrained) and add a big - comment explaining this change, remove unused only_resize variable - and irrelevant huge FIXME comment about it - - * src/window.[ch] (meta_window_get_client_root_coords): - new function - - * src/display.c (meta_display_begin_grab_op): - * src/keybindings.c (process_keyboard_move_grab): - * src/window.c (meta_window_unmaximize, - meta_window_move_resize_internal, meta_window_begin_wireframe, - update_move, meta_window_refresh_resize_popup, - warp_grab_pointer) - combine multi-step client rect root coord setting into a single - function call to meta_window_get_client_root_coords() - -2007-04-08 Thomas Thurman <thomas@thurman.org.uk> - - * ChangeLog: removed conflict line. - -2007-04-07 Elijah Newren <newren gmail com> - - * src/prefs.[ch] (screen_bindings array, - META_KEYBINDING_SET_SPEW_MARK definition): - * src/keybindings.c (handle_spew_mark, screen_handlers array): - Add an (unbound by default) keybinding for setting spew marks in - verbose debugging logs. I'm not sure why this was ever removed; - I've wanted it so many times. - - * HACKING: - valgrind wants --log-file not --logfile. - -2007-04-07 Elijah Newren <newren gmail com> - - * src/window.c (meta_window_free): Fix memory bug (invalid free) - introduced in 2007-04-02 strut cleanup commit. Part of #427385. - -2007-04-05 Thomas Thurman <thomas@thurman.org.uk> - - * src/theme_parser.c: if theme is invalid and therefore got - freed, don't attempt to read from it. Closes #423855. - -2007-04-05 Bastien Nocera <hadess@hadess.net> - - * src/50-metacity-desktop-key.xml.in: - * src/50-metacity-key.xml.in: - * src/Makefile.am: - Add new control-center key bindings definitions (Closes: #420145) - -2007-04-04 Elijah Newren <newren gmail com> - - * configure.in: post-release bump to 2.19.2. - -2007-04-04 Elijah Newren <newren gmail com> - - * NEWS: 2.19.1 release. - -2007-04-04 Elijah Newren <newren gmail com> - - * src/window.c (meta_window_move_resize_internal): send synthetic - configurenotify events also in response to MapRequest events when - the window has a frame and the application specifies PPosition or - UPosition hints. I believe they are already sent for all other - cases. Should fix #322840. Fixes the testcase at least. :) - -2007-04-04 Elijah Newren <newren gmail com> - - Fix lots of little issues with min/max constraints and size - increment constraints. Fixes #329152, #418395, and possibly - others. - - * src/window-props.c (meta_set_normal_hints): - Do more checking to make sure application specified constraints - are self-consistent, modifying the size_hints as necessary to - achieve self-consistency. - - * src/constraints.c (setup_constraint_info): remove ugly - copy-pasto, (constrain_size_increments): be careful that fixing - violation of the constraints doesn't cause a violation of the - minimum size constraints. - - * src/window.c (ensure_size_hints_satisfied): new function, - (meta_window_unmaximize, meta_window_unmake_fullscreen): the - saved_rect may no longer be valid (as in the case of #329152) so - call ensure_size_hints_satisfied to fix it up. - - * doc/how-to-get-focus-right.txt: Some minor spacing and wording - fixes completely unrelated to the rest of this commit - -2007-04-03 Elijah Newren <newren gmail com> - - * src/window.c (meta_window_unmaximize): - Only use saved_rect for determining the position to unmaximize to - for the previously-maximized direction(s). Fixes #355497. - -2007-04-03 Elijah Newren <newren gmail com> - - * MAINTAINERS: Update. #412319. - -2007-04-03 Elijah Newren <newren gmail com> - - * src/display.c (meta_display_update_active_window_hint): - _NET_ACTIVE_WINDOW is a single xwindow id, not two. - -2007-04-03 Elijah Newren <newren gmail com> - - * src/keybindings.c (handle_panel_keybinding): turn mouse_mode off - to prevent focus issues with the run application dialog. Fixes - #374752. - -2007-04-03 Elijah Newren <newren gmail com> - - Avoid some crashes when dragging windows partially offscreen. - Possible (or at least partial) fix for #353513. - - * src/edge-resistance.c (apply_edge_resistance): be more careful - about calls to find_index_of_edge_near_position() returning - possibly invalid indices. Also, add a warning comment to - find_index_of_edge_near_position(). - -2007-04-03 Elijah Newren <newren gmail com> - - Patch from Carlo Wood to do some miscellaneous code cleanups found - while working on #358311. - - * src/constraints.c (do_screen_and_xinerama_relative_constraints): - nicer way of avoiding compilation warning - - * src/boxes.c (meta_rectangle_clamp_to_fit_into_region, - meta_rectangle_clip_to_region, meta_rectangle_shove_into_region): - Much cleaner way of ignoring invalid boxes in comparisons - -2007-04-02 Elijah Newren <newren gmail com> - - Patch from Carlo Wood to fix handling of unidirectional - maximization and partial struts. #358311. - - * src/constraints.c (constrain_maximization): - determine target size for unidirectionally maximized windows by - determining how far they can be maximized without hitting - orthogonal struts. Avoids weird "empty spaces". - - * src/boxes.[ch] (meta_rectangle_expand_to_avoiding_struts): - new function - -2007-04-02 Elijah Newren <newren gmail com> - - Make the strut lists (stored in workspaces) record both the - rectangle and the side that the strut is on. Lots of code - cleanups relating to struts. - - * src/boxes.h (struct MetaStrut): - new struct for struts - - * src/window.[ch] (struct MetaStruts, struct MetaWindow, - meta_window_update_struts): - overhaul to make window's struts remember their side as well as - their rectangular location, and just use a list instead of several - copies of near-identical code for left/right/top/bottom (allowing - us to nuke MetaStruts struct as well) - - * src/testboxes.c (new_meta_strut, get_strut_list): - * src/workspace.c (ensure_work_areas_validated): - * src/boxes.c (meta_rectangle_get_minimal_spanning_set_for_region, - meta_rectangle_expand_to_avoiding_struts, - get_disjoint_strut_rect_list_in_region, fix_up_edges, - meta_rectangle_find_onscreen_edges, - meta_rectangle_find_nonintersected_xinerama_edges): - modify to handle struts being rectangle + side instead of just rectangle - - * src/workspace.c (ensure_work_areas_validated): - simplify strut list creation considerably given MetaWindow change, - modify work_area computations to take advantage of region - computations being done (makes the code shorter as well as more - robust against pathological cases). - - * src/util.[ch] (meta_free_gslist_and_elements): - new convenience function - - * src/common.h (enum MetaDirection): - * src/edge-resistance.c (movement_towards_edge): - * src/boxes.c (meta_rectangle_edge_aligns, - rectangle_and_edge_intersection, split_edge): - Add more MetaDirection fields for convenience - - * src/boxes.h (enum FixedDirections): - * src/constraints.c (setup_constraint_info, place_window_if_needed): - add a FIXED_DIRECTION_NONE to the FixedDirections enum to make - code more clear - -2007-04-01 Bruno Boaventura <brunobol@gnome.org> - - * src/theme.c (kill_window_question): Fallback to NORMAL state after - checking for the middle button. Fixes bug #419043. - Patch from Benjamin Berg <benjamin@sipsolutions.net>. - -2007-03-31 Elijah Newren <newren gmail com> - - Clean up event mask handling and meta_create_offscreen_window, to - prevent nasty metacity/gdk interactions causing hangs. See #354213. - - * src/screen.[ch] (meta_create_offscreen_window): - * src/display.c (meta_display_open): - * src/screen.c (meta_screen_new): - Add a valuemask parameter to meta_create_offscreen_window - - * src/display.c (meta_display_open): - make it explicit that we can't rely on PropertyNotify events for - the leader_window due to nasty metacity/gdk interaction - - * src/session.c (warn_about_lame_clients_and_finish_interact): - remove cut-and-paste code for timestamp pinging and just call - meta_display_get_current_time_roundtrip - -2007-03-30 Elijah Newren <newren gmail com> - - Add support for _NET_WM_USER_TIME_WINDOW in order to cut down on - context switches. Fixes #354213. - - * src/display.c (meta_display_open): - * src/display.h (struct _MetaDisplay): - * src/screen.c (set_supported_hint): - new atom - - * src/display.c (meta_display_open, - meta_display_get_current_time_roundtrip): - * src/display.h (struct _MetaDisplay): - create a dedicated timestamp pinging window instead of reusing - display->leader_window - - * src/display.c (event_callback): - * src/window-props.c (reload_net_wm_user_time_window): - * src/window.c (meta_window_new_with_attrs, meta_window_free, - process_property_notify): - * src/window.h (struct _MetaWindow): - monitor property notify events on _NET_WM_USER_TIME_WINDOW windows too - - * src/window-props.[ch]: - new meta_window_reload_propert(y|ies)_from_xwindow() functions - - * src/window-props.[ch] - (init_net_wm_user_time_window, reload_net_wm_user_time_window, - meta_display_init_window_prop_hooks): - * src/window.c (meta_window_new_with_attrs): - new hooks to handle new atom - -2007-03-26 Josselin Mouette <joss@malsain.org> - - * src/session.c (meta_session_init): if previous client ID - was supplied, use it in filename. - * src/session.c (set_clone_restart_commands): use --sm-client-id - in command line to restore session, not original file name. - * src/session.c (regenerate_save_file): generate filename using - client ID and not original file name. - * src/session.c (base_save_file): removed function. - Closes GNOME 407981, Debian 391287, Debian 315169. - -2007-03-25 Elijah Newren <newren gmail com> - - * configure.in: bump version to 2.19.1; doesn't make sense to have - the development version have a version number less than the stable - version. ;-) - -2007-03-20 Arthur Taylor <theycallhimart@gmail.com> - - * src/frames.c (meta_frames_apply_shapes): adjusted the rounded - corners so that they fit nicely with the arcs around them. - Fixes #399373. - -2007-03-17 Kjartan Maraas <kmaraas@gnome.org> - - * src/ui.c: Remove #include <pango/pangox.h> since it's - apparently not installed anymore. Builds just fine without it too. - -2007-03-10 Charlie Brej <cbrej@cs.man.ac.uk> - - * src/metacity.schemas.in: add action_{middle|right}_click_titlebar. - Closes #408903. - -2007-03-09 Linus Torvalds <torvalds@woody.linux-foundation.org> - - * src/frames.c (meta_frame_middle_click_event, - meta_frame_right_click_event): honour preferences. - * src/prefs.[ch] (meta_prefs_get_action_middle_click_titlebar, - meta_prefs_get_action_right_click_titlebar): new functions. - -2007-02-20 Kjartan Maraas <kmaraas@gnome.org> - - * Makefile.am: Add MAINTAINERS to EXTRA_DIST so others - can find out where to send patches. Hi Linus :-) - -2007-02-17 Linus Torvalds <torvalds@woody.linux-foundation.org> - - * src/common.h (MetaActionTitleBar): renamed from - MetaActionDoubleClickTitleBar; added _LOWER and _MENU. - * src/frames.c (meta_frame_titlebar_event): renamed - enums as above; added code to handle _LOWER and _MENU, - which is moved in from meta_frame_{middle|right}_click_event. - * src/frames.c (meta_frame_middle_click_event, - meta_frame_right_click_event): rewrote in terms of - meta_frame_titlebar_event. - * src/prefs.c: removed "DoubleClick" from names as above. - * src/prefs.c (action_titlebar_from_string): added cases - for "lower" and "menu". - Fixes #408902. - -2007-02-17 Linus Torvalds <torvalds@woody.linux-foundation.org> - - * src/frames.c (meta_frames_button_press_event): Split out - code for different kinds of click into separate functions. - Fixes #408899. - * src/frames.c (meta_frame_titlebar_event, - meta_frame_double_click_event, meta_frame_middle_click_event, - meta_frame_right_click_event): new functions. - -2007-01-27 Bruno Boaventura <brunobol@gnome.org> - - * src/metacity-dialog.c (kill_window_question): Change dialog - icon because gnome-icon-theme have no more "panel-force-quit". - Patch from Jaap A. Haitsma <jaap@haitsma.org>. - -2007-01-16 Thomas Thurman <thomas@thurman.org.uk> - - * doc/compositor-control.txt: fix silly thinko. - -2007-01-16 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.17.8. - -2007-01-16 Thomas Thurman <thomas@thurman.org.uk> - - * doc/compositor-control.txt: New file. - -2007-01-16 Thomas Thurman <thomas@thurman.org.uk> - - * src/compositor.c (meta_compositor_new): Removed - #ifdef SPIFFY_COMPOSITOR throughout the file. Replaced with check - for environment variable METACITY_BLING, which may be temporary. - -2007-01-13 Bruno Boaventura <brunobol@gnome.org> - - * src/frames.c (meta_frames_motion_notify_event): Unmaximize - button must keep preesed appearence when clicked (hold down), - move off, and back over the button. Fixes #395560. Patch from - Mad Alex <madalexonline@yahoo.co.uk>. - -2007-01-02 Thomas Thurman <thomas@thurman.org.uk> - - * src/c-screen.c (meta_comp_screen_redirect): Remove double unref - of stacker object. Fixes #387761. - -2006-12-27 Bruno Boaventura <brunoboaventura@gmail.com> - - Move "On Top" option in menu. Fix #382962. - - * src/common.h, src/core.c: Remove META_MENU_OP_UNABOVE. - * src/menu.c: remove unabove menu item and put above item - next "Always on Visible Viewport". - * src/window.c: remove handles of META_MENU_OP_UNABOVE. - -2006-12-21 Thomas Thurman <thomas@thurman.org.uk> - - * src/compositor.c: Disabled bling for now; added function for - handling CirculateNotify XEvent; some commenting. - * src/compositor.h, src/c-window.c: fix function prototype visibility. - -2006-12-12 Thomas Thurman <thomas@thurman.org.uk> - - * src/compositor.c (do_effect): Sanity check to avoid dereferencing - a null pointer. - -2006-12-10 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.17.5. - -2006-12-10 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.17.3 release. - -2006-12-05 Christof Krüger <mail@pop2wap.net> - - * src/window.c (update_move): Fix flickering about when dragging - maximised windows between xineramas. Closes #358715. - -2006-12-03 Federico Mena Quintero <federico@novell.com> - - Fix http://bugzilla.gnome.org/show_bug.cgi?id=381127: - - * src/window.c (idle_calc_showing): Grab the server while the - windows are being shuffled. First show the windows to be shown, - and then hide the windows to be hidden, in order to minimize - the number of expose events. - -2006-11-15 Bruno Boaventura <brunoboaventura@gmail.com> -2006-11-15 Björn Lindqvist <bjourne@gmail.com> - - * src/menu.c: added MetaMenuItemType enum; added it - to MenuItem; added values of this type to menuitems - array. - * src/menu.c (menu_item_new): rewrite to take a MenuItem - instead of a set of parameters describing the menu item. - * src/menu.c (meta_window_menu_new): use proper checkboxes - or radio buttons on the window menu. (#343108) - * src/window.c (meta_window_show_menu): unstick and stick - are always shown. - -2006-11-06 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.17.3. - -2006-11-06 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: pre-release bump to 2.17.2. - * NEWS: 2.17.2 release. - -2006-11-05 Priit Laes <amd@store20.com> - - * src/main.c, src/ui.c: remove deprecated gtk stuff. - -2006-11-05 Bruno Boaventura <brunoboaventura@gmail.com> - - * src/theme.c, src/testgradient.c: remove deprecated gtk stuff. - -2006-11-05 Kjartan Maraas <kmaraas@gnome.org> - - * src/ui.c: use g_strdup to allocate a string, not strdup. Fixes - #363354. - * src/metacity-dialog.c: add missing spaces to string. Fixes - #363355. - -2006-11-05 Justin Mason <jm@jmason.org> - - * src/keybindings.c: implement handle_move_to_{side|corner}_* to - allow the user to flip a window to the side or corner of the - screen. Fixes #317884. - * src/prefs.h: keybindings for the above. - * src/metacity.schemas.in: keybindings for the above. - -2006-11-05 Elijah Newren <newren gmail com> - - * src/frames.c: improved rounding of rounded corners. Fixes #360542, - mostly. - -2006-10-30 Dan Mick <dan.mick@sun.com> - - * src/window.c: (__window_is_terminal): Fix strict focus - mode by picking up on res_class. Fixes #361054, strict focus - mode still not working; should look for res_class, not res_name - -2006-10-16 Elijah Newren <newren gmail com> - - * NEWS: 2.17.1 release. - -2006-10-13 Carlo Wood <carlo@alinoe.com> - - Fix cases when titlebar is allowed offscreen and shouldn't be (and - vice-versa). #333995. - - * src/display.[ch] (struct _MetaDisplay): add grab_frame_action - member - - * src/display.[ch] (meta_display_begin_grab_op): - * src/window.[ch] (meta_window_begin_grab_op): - * src/core.[ch] (meta_core_begin_grab_op): - Add frame_action parameter (core & window versions pass it on to - display) - - * src/display.c (event_callback): - * src/window.c (meta_window_begin_grab_op, - meta_window_client_message, menu_callback): - * frames.c (meta_frames_button_press_event): - * keybindings.c (do_choose_window, handle_begin_move, - handle_begin_resize, handle_workspace_switch): - Pass whether the action should be considered a 'frame_action', - which will be used to determine whether to force the titlebar to - remain onscreen, to meta_*_begin_grab_op - - * constraints.c (constrain_titlebar_visible): - Replace previous ugly hack by using grab_frame_action (and whether - the action is a user action) to determine whether to enforce the - titlebar_visible constraint. - -2006-10-10 Elijah Newren <newren gmail com> - - * src/draw-workspace.c (draw_window, wnck_draw_workspace): Patch - from Bruno Boaventura to sync metacity workspace previews with - libwnck. #341893 - -2006-10-07 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.17.1. - -2006-10-07 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.17.0 release. - -2006-10-07 Thomas Thurman <thomas@thurman.org.uk> - - * src/themes/Crux/metacity-theme-2.xml: removed hide_buttons. - Closes #360498. - -2006-10-07 Thomas Thurman <thomas@thurman.org.uk> - - * MAINTAINERS: added myself. - -2006-10-07 Thomas Thurman <thomas@thurman.org.uk> - - * doc/theme-format.txt: described new theme format. - - * src/themes/Bright, src/themes/Crux: added version 2 themes. - -2006-10-07 Thomas Thurman <thomas@thurman.org.uk> - - * common.h: Added "above" to the list of flags a frame can have, so - that we know when to mark it as always on top. Added six grab ops, - one to do and one to undo each of the three new titlebar buttons - (shade, above, stick). Added six new button functions, similarly. - (#96229) - - * frame.c (meta_frame_get_flags): If a frame has the WM_STATE_ABOVE X - attribute, set META_FRAME_ABOVE in its flags. - - * frames.c (meta_frames_apply_shapes): Allow variable amounts of - rounding. (#113162) - - * frames.c (show_tip_now, meta_frames_paint_to_drawable, control_rect, - get_control): extend handling of existing buttons to the - 3*2 new kinds of button. (#96229) - - * frames.c (meta_frames_button_press_event): translate clicks on the 3*2 - new kinds of button to the new grab ops. (#96229) - - * frames.c (meta_frames_button_release_event): implement the various - actions for the 3*2 new kinds of button. (#96229) - - * frames.c (meta_frames_update_prelit_control, - meta_frames_motion_notify_event): extend existing motion - notifications for buttons to the 3*2 new kinds of button. (#96229) - - * frames.c (meta_frames_set_window_background): handle specified - background colours and alpha transparency. (#151261) - - * frames.h (MetaFrameControl): New control types for the 3*2 new kinds - of button. (#96229) - - * iconcache.[ch] (meta_read_icons): use theme's fallback icons if a - window has no icon; use metacity's fallback icons only if the theme - does not provide any. (#11363) - - * iconcache.[ch] (meta_invalidate_default_icons (new function)): clear - icon cache on windows using default icons, and update them. (#11363) - - * main.c (main): added \n to error message. - - * prefs.c (button_function_from_string): extend for 3 new button - types. (#96229) - - * prefs.c (button_opposite_function (new function)): return a button - function's inverse (shade -> unshade, etc) (#96229) - - * prefs.c (update_button_layout): allocate space for a button's - inverse, if it has one. (#96229) - - * theme-parser.c (ParseState): add state for fallback icons (#11363) - - * theme-parser.c (ParseInfo): add format_version; remove - menu_icon_* (#114305) - - * theme-parser.c (parse_positive_integer): add lookup for integer - constants (#331356) - - * theme-parser.c (parse_rounding (new function)): parse window - rounding amount (#113162) - - * theme-parser.c (parse_alpha): don't set error if the number can't - be parsed since it'll already be set; change tolerance in comparison - from 1e6 to 1e-6 - - * theme-parser.c (parse_color (new function)): parse colour, including - possible constant lookup. - - * theme-parser.c (parse_toplevel_element): allow defining of various - new kinds of constant; allow - hide_buttons (#121639) and more detailed rounding attributes on - <frame_geometry> (#113162); allow background and alpha attributes on - <frame_style>; (#151261) remove support for <menu_icon> except as - stub; (#114305) add support for loading stock images (#113465); add - support for <fallback>. (#11363)) - - * theme-parser.c (parse_draw_op_element): add from and to attribute - for arcs. (#121603) - - * theme-parser.c (parse_style_element): add check for theme version - supporting a button function. (#96229) - - * theme-parser.c (parse_style_set_element): add ability for shaded - windows to be resizable (#114304) - - * theme-parser.c (meta_theme_load): add theme versioning routine. - - * theme.c ( meta_frame_layout_get_borders): return rectangles for - the new 3*2 kinds of button, except where they're - inapplicable. (#96229) - - * theme.c (meta_frame_layout_calc_geometry): don't format buttons on - windows with no buttons (#121639); strip the 3*2 new kinds of button - correctly (#96229); allow variable amounts of rounding (#113162). - - * theme.c (meta_frame_style_new): set alpha to 255 by - default. (#151261) - - * theme.c (meta_frame_style_unref): free colour spec if - allocated. (#151261) - - * theme.c (meta_frame_style_validate): it's only an error not to - include a button if that button is valid in the current - theme. (#96229) - - * theme.c (button_rect): return rectangles for the new 3*2 kinds - of button. (#96229) - - * theme.c (meta_frame_style_set_unref): free differently resizable - shaded styles. (#114304) - - * theme.c (get_style): look up differently resizable styles - for shaded windows. (#114304) - - * theme.c (free_menu_ops (removed function), get_menu_icon - (removed function), meta_theme_draw_menu_icon (removed function), - meta_menu_icon_type_from_string (removed function), - meta_menu_icon_type_to_string (removed function), - meta_theme_free, meta_theme_validate): removed menu icon code. (#114305) - - * theme.c (meta_theme_load_image): add size_of_theme_icons - parameter. (#113465) - - * theme.c (meta_theme_define_color_constant (new function), - meta_theme_lookup_color_constant (new function)): allow - definition of colour constants. (#129747) - - * theme.c (meta_button_type_from_string, meta_button_type_to_string): - add the 3*2 new kinds of button. (#96229) - - * theme.c (meta_theme_earliest_version_with_button (new function)): - return the theme version each button was introduced in. (#96229) - - * theme.h ( MetaFrameLayout): add "hide_buttons" flag (#121639) and - corner radiuses. (#113162) - - * theme.h (MetaFrameGeometry): add rectangles for the 3*2 new - buttons. (#96229) - - * theme.h (MetaButtonType): the 3*2 new buttons. (#96229) - - * theme.h (MetaFrameStyle): add window_background_color and - window_background_alpha so that we can specify background on a - <frame_style>. (#151261) - - * theme.h (MetaFrameStyleSet): shaded_styles gets resize - dimension. (#114304) - - * theme.h (MetaTheme): added format_version, color_constants - hash, (#129747) fallback_icon and fallback_mini_icon, (#11363) - and removed menu_icons. (#114305) - - * theme.h (META_THEME_ALLOWS (new macro)): return whether a theme - supports a given feature. Also, several macros representing - new features in v2. - - * ui.c (meta_ui_set_current_theme)): also invalidate default - icons. (#11363) - - * window.[ch] (meta_window_update_icon_now)): became - non-static. (#11363) - -2006-10-06 Elijah Newren <newren gmail com> - - * src/metacity-dialog.c (kill_window_question): Be nice to - translators; remove unnecessary markup from strings marked for - translation (oops, I missed this in my review before previous - commit) - -2006-10-06 Elijah Newren <newren gmail com> - - * src/metacity-dialog.c (kill_window_question): Patch from Bruno - Boaventura to improve the "Force Quit" dialog. #121936 - -2006-10-02 Elijah Newren <newren gmail com> - - Ignore edge resistance for size-increment windows when resizing - with the keyboard. #346782. - - * src/edge-resistance.c (apply_edge_resistance_to_each_side): - ignore edge resistance for size-increment windows when resizing - with the keyboard, (apply_edge_resistance_to_each_side, - meta_window_edge_resistance_for_move, - meta_window_edge_resistance_for_resize): pass a is_resize - parameter as well - -2006-10-01 Elijah Newren <newren gmail com> - - * src/display.c (meta_display_set_input_focus_window): - * src/window.c (meta_window_focus): - Don't require a push/pop trap around - meta_display_set_input_focus_window(), but rather move the - push/pop into that function surrounding the XSetInputFocus() call - directly. Follow up to #358514. - -2006-10-01 Elijah Newren <newren gmail com> - - * src/*.[ch]: Stick an emacs comment directive at the beginning of - all the code files so that people using emacs will be more likely - to get coding style correct in their patches. We still need a - similar vi directive. #358866 - -2006-10-01 Elijah Newren <newren gmail com> - - Patch from Carlo Wood to ensure that maximized and minimized - properties are maintained across restarts. #358042. - - * src/constraints.c (place_window_if_needed): fix up partial - maximization handling and add minimize_after_placement handling. - - * src/display.[ch] (struct MetaDisplay, meta_display_open): add a - new display->display_opening flag to allow handling startup - differently where needed. - - * src/window-props.c (reload_net_wm_state): handle - _net_wm_state_hidden as well, setting - window->minimize_after_placement appropriately - - * src/window.[ch] (struct MetaWindow, meta_window_new_with_attrs): - add a window->minimize_after_placement field - - * src/window.c (meta_window_new_with_attrs): only unminimize the - window and its transients if the display isn't being opened, - (unmaximize_window_before_freeing): don't reset the state unless - the window is becoming withdrawn, if the screen is being closed be - sure to save the unmaximized state of the window so the next - window manager can restore it - -2006-10-01 Elijah Newren <newren gmail com> - - * src/window-props.c (set_title_text): surround the - XDeleteProperty() call with a - meta_error_trap_push/meta_error_trap_pop pair to prevent a crash - when closing a remote instance of gedit (and perhaps other apps). - #358514. - -2006-10-01 Elijah Newren <newren gmail com> - - Fix longstanding focus bug with mouse (not sloppy) focus mode with - popup override-redirect windows, particularly mozilla and - firefox's location bar autocompletion. #357695. - - * src/display.c (event_callback -- EnterNotify & LeaveNotify events): - for mouse focus, defocus the focused window when the mouse enters - the desktop window rather than when the mouse leaves the focused - window. - - * doc/how-to-get-focus-right.txt: - update for the slightly nuanced definition of mouse focus (people - without a DESKTOP window like nautilus get sloppy focus behavior - now) - -2006-09-27 Elijah Newren <newren gmail com> - - * src/menu.c (var menuitems): Patch from Bruno Boaventura to add - notes to remind translators to keep translations in sync with - libwnck. #355620. - -2006-09-18 Elijah Newren <newren gmail com> - - * src/window.c (meta_window_show): Patch from Jens Granseuer to - fix c89 cleanness, again. #356631. - -2006-09-18 Elijah Newren <newren gmail com> - - * src/constraints.c (constrain_maximization): Ignore maximum size - hints when maximizing. Should fix #327543 (see comment 4 and comment - 5). - -2006-09-18 Elijah Newren <newren gmail com> - - * src/ui.c (filter_func): avoid a compilation warning by making - sure to return something. #348067 - -2006-09-18 Thomas Thurman <thomas@thurman.org.uk> - - Branched for Gnome 2.17. - - * configure.in: bump version to 2.17.0. - -2006-09-18 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.16.3 - -2006-09-18 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.16.2 release - -2006-09-18 Elijah Newren <newren gmail com> - - Partial audit to fix timestamp usage. One step towards fixing - #355180; see important comments in that bug. - - * src/core.[ch] (meta_core_unshade, meta_core_shade): - * src/delete.c (meta_window_present_delete_dialog, - delete_ping_timeout_func): - * src/display.[ch] (meta_display_open, meta_display_close, - event_callback, meta_display_begin_grab_op, - process_selection_clear, meta_display_unmanage_screen, - meta_display_unmanage_windows_for_screen): - * src/frames.c (meta_frames_button_press_event): - * src/keybindings.c (handle_toggle_shade): - * src/main.c (main): - * src/screen.[ch] (update_num_workspaces, meta_screen_new, - meta_screen_free, prefs_changed_callback): - * src/window.[ch] (meta_window_free, finish_minimize, - implement_showing, meta_window_show, meta_window_maximize, - meta_window_make_fullscreen_internal, - meta_window_unmake_fullscreen, meta_window_shade, - meta_window_unshade, window_activate, send_sync_request, - meta_window_client_message, menu_callback, - meta_window_update_keyboard_resize): - Remove usage of CurrentTime, meta_display_get_current_time() and - meta_display_get_current_time_roundtrip() where possible, or - document why it isn't possible, or at very least add a FIXME with - some explanation of my laziness and what needs to be done. - -2006-09-18 Elijah Newren <newren gmail com> - - * src/spring-model.c (on_end_move, model_is_calm): Patch from Maik - Beckmann to remove compilation warnings. Fixes #355876. - -2006-09-18 Elijah Newren <newren gmail com> - - * configure.in: Make detection of stable vs. unstable automatic - and based upon the version number. Partially based on patch from - Christian Hamar in #356122. Fixes #356122. - -2006-09-13 Elijah Newren <newren gmail com> - - * HACKING: update -- we depend on gtk+ >= 2.10 since Vincent's - July patches for #348633. - -2006-09-13 Elijah Newren <newren gmail com> - - * src/window.c (meta_window_show): Patch from Thomas Andersen to - make windows be stacked correctly before showing them, to prevent - flicker with focus stealing prevention. #332385. - -2006-09-13 Elijah Newren <newren gmail com> - - * src/common.h (MetaWindowMenuFunc): - * src/core.[ch] (meta_core_user_lower_and_unfocus, - meta_core_user_focus, meta_core_show_window_menu, - meta_core_begin_grab_op, meta_core_end_grab_op): - * src/delete.c (delete_ping_reply_func, delete_ping_timeout_func, - meta_window_delete): - * src/display.[ch] (struct MetaDisplay, struct MetaPingData, - sanity_check_timestamps, meta_display_open, event_callback, - meta_spew_event, meta_display_set_grab_op_cursor, - meta_display_begin_grab_op, meta_display_end_grab_op, - meta_display_ping_timeout, meta_display_ping_window, - process_pong_message, timestamp_too_old, - meta_display_set_input_focus_window): - * src/keybindings.[ch] (grab_keyboard, ungrab_keyboard, - meta_screen_grab_all_keys, meta_window_grab_all_keys, - meta_window_ungrab_all_keys, error_on_generic_command, - error_on_command, error_on_terminal_command): - * src/metacity-dialog.c (on_realize, warn_about_no_sm_support, - error_about_command, main): - * src/screen.[ch] (struct _MetaScreen, meta_screen_new, - meta_screen_show_desktop, meta_screen_apply_startup_properties): - * src/session.c (warn_about_lame_clients_and_finish_interact): - * src/window.[ch] (struct _MetaWindow, - intervening_user_event_occurred, window_activate, - meta_window_delete, meta_window_focus, - meta_window_send_icccm_message, meta_window_client_message, - menu_callback, meta_window_show_menu, struct EventScannerData, - check_use_this_motion_notify, meta_window_begin_grab_op, - meta_window_set_user_time): - * src/workspace.[ch] (focus_ancestor_or_mru_window, - meta_workspace_activate_with_focus, meta_workspace_activate, - meta_workspace_focus_default_window, - focus_ancestor_or_mru_window): - Fix issues on 64-bit machines with timestamps by using guint32 - (like gtk+ does) instead of Time. #348305 - -2006-09-12 Elijah Newren <newren gmail com> - - * src/theme.c (meta_gtk_arrow_from_string, - meta_gtk_arrow_to_string): patch from Bruno Boaventura de Oliveira - to fix a compiler warning about not handling GTK_ARRROW_NONE. - #355490. - -2006-09-12 Elijah Newren <newren gmail com> - - * src/compositor.c: Patch from Bruno Boaventura de Oliveira - Lacerda to fix warnings about unused function and global var. - #355489. - -2006-09-11 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release bump to 2.16.2 - -2006-09-11 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.16.1 release - -22006-09-09 Elijah Newren <newren gmail com> - - * src/display.c (meta_display_open): Fix build when XKB not found. - #354211 - -2006-09-09 Elijah Newren <newren gmail com> - - Avoid a stuck grab, preventing focus from being transferred - between windows. Thanks to Fryderyk Dziarmagowski for steps to - reproduce. Fixes at least part of #354422. - - * src/display.c (meta_display_begin_grab_op, - meta_display_end_grab_op): pass timestamp to - meta_screen_ungrab_all_keys, meta_screen_ungrab_all_keys, and - meta_window_ungrab_all_keys - - * src/keybindings.[ch] (grab_keyboard, ungrab_keyboard): add a - timestamp parameter and remove call to - meta_display_get_current_time(), (meta_screen_grab_all_keys, - meta_screen_ungrab_all_keys, meta_window_ungrab_all_keys): add a - timestamp parameter and pass it on to grab_keyboard and - ungrab_keyboard - -2006-09-07 Elijah Newren <newren gmail com> - - * src/constraints.c (update_onscreen_requirements): make sure - windows returning from fullscreen mode are constrained to be - "onscreen"; fixes #353699. - -2006-08-30 Colin Watson <cjwatson@ubuntu.com> - - * src/window-props.c (reload_transient_for): Clear - window->xtransient_for after emitting the invalid window warning. - #353540 - -2006-09-07 Elijah Newren <newren gmail com> - - * src/metacity-dialog.c: Patch from Bruno Boaventura de Oliveira - Lacerda to replace copy_of_gdk_x11_window_set_user_time() with - gdk_x11_window_set_user_time(). We've long since adopted gtk+ >= - 2.6 as a dependency. #352293 - -2006-09-04 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release version bump to 2.16.1 - -2006-09-04 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.16.0 release - -2006-08-22 Elijah Newren <newren gmail com> - - * src/metacity-dialog.c (main): Patch from Jens Granseuer to fix - the build with c89/gcc 2.95. - -2006-08-21 Elijah Newren <newren gmail com> - - * NEWS: Oops, forgot to mention the translators in the 2.15.34 - release; add them retroactively - -2006-08-21 Elijah Newren <newren gmail com> - - * configure.in: post-release version bump to 2.15.55 - -2006-08-21 Elijah Newren <newren gmail com> - - * NEWS: 2.15.34 release - -2006-08-21 Elijah Newren <newren gmail com> - - Patch from Thomas Andersen to fix metacity-dialog handling of - arguments. #340690 - - * src/metacity-dialog.c (main): replace hackish argument parsing - with GOption parsing. Much nicer. :) - -2006-08-21 Elijah Newren <newren gmail com> - - Patch from Ed Catmur to fix keybindings with hex-values (coming - from special extended keyboard keys). #140448. - - * src/keybindings.c (struct _MetaKeyBinding): change keycode from - KeyCode to unsigned int (comment from Elijah: why???), - (reload_keycodes): only grab keysyms for keybindings that have - them, (count_bindings, rebuild_binding_table): bindings can be - valid either due to a valid keysym or a valid keycode, - (display_get_keybinding_action, meta_change_keygrab, - process_tab_grab, process_workspace_switch_grab): handle keycode - as well as keysym - - * src/prefs.[ch] (struct MetaKeyCombo, update_binding, - update_list_binding): handle keycode as well as keysym - - * src/ui.[ch] (meta_ui_accelerator_parse): new function special - cases strings of the form "0x[0-9a-fA-F]+" and otherwise calling - gtk_accelerator_parse(), (meta_ui_parse_accelerator, - meta_ui_parse_modifier): call meta_ui_accelerator_parse instead of - gtk_accelerator_parse. - -2006-08-21 Elijah Newren <newren gmail com> - - Allow drags & resizes to be reverted by hitting escape. Based on - patch from Thomas Andersen. #126497. - - * src/display.c (grab_op_is_mouse_only): new function, - (meta_display_begin_grab_op): grab the keyboard when moving or - resizing too so that we can get escape keypresses - - * src/display.h (struct _MetaDisplay): add a comment to remind - that grab_was_cancelled is only used in wireframe mode - - * src/keybindings.[ch] (process_mouse_move_resize_grab): add new - function for handling keypresses during mouse-only moving and - resizing, (meta_window_grab_all_keys): add a timestamp parameter - and pass it to meta_window_focus(), - (meta_display_process_key_event): make sure - process_mouse_move_resize_grab() gets called when needed, - (process_keyboard_move_grab, process_keyboard_resize_grab): - rearrange some code slightly and improve the comments to make it - more readable - -2006-08-21 Elijah Newren <newren gmail com> - - Fix several bugs with handling of fullscreen windows, causing them - to not actually be fullscreen. #343115 (and also #346927, - #350547, #351643, the recent additional WINE-related issue - mentioned on the mailing list, and probably others...) - - * src/constraints.c (setup_constraint_info): if a window tries to - resize to fullscreen-size and it has a fullscreen function but - isn't actually marked as fullscreen then assist it by marking it - as such, (constrain_fully_onscreen, constrain_titlebar_visible): - ignore this constraint for fullscreen windows since such windows - have a separate specialized constraint - - * src/stack.c (window_is_fullscreen_size, get_standalone_layer): - remove the old window_is_fullscreen_size() hack for detecting - windows to treat as fullscreen since it doesn't work well with the - new constraints framework (i.e. we needed a slightly different - hack) - - * src/window.[ch] (meta_window_new_with_addrs): shuffle the order - of adding the window to the stack and moveresizing the window - since moveresizing can cause stack changes if the window's initial - size is fullscreen size, (meta_window_make_fullscreen, - meta_window_make_fullscreen_internal): split - meta_window_make_fullscreen() similar to meta_window_maximize() so - that constraints can make use of it - -2006-08-19 Baptiste Mille-Mathias <baptiste.millemathias@gmail.com> - - * src/stock_delete.png: Update the pixmap to a new one which - fit better with the other pixmaps of the menu. First patch in - metacity, woot! #345498 - -2006-08-18 Elijah Newren <newren gmail com> - - * src/tabpopup.c (meta_ui_tab_popup_new): Patch from Willie Walker - to restore the part of the patch that I should not have reverted - in #123372, in order to fix accessibility. #350624 - -2006-08-09 Elijah Newren <newren gmail com> - - * src/window.c (intervening_user_event_occurred): Vytautus Liuolia - totally rocks; he tested and debugged and tracked down where we - were using the focus window's net_wm_user_time even when it was - uninitialized. This may fix bug 311868 and others I've heard - about (with Valknut, IIRC). It definitely fixes the issues Vytas - was seeing with his single instance library. :-) - -2006-08-07 Elijah Newren <newren gmail com> - - * src/constraints.c (setup_constraint_info): patch from Stéphane - Rosi to allow moving maximized windows between xineramas again. - #323820 - -2006-08-07 Elijah Newren <newren gmail com> - - * configure.in: post-release version bump to 2.15.34 - -2006-08-07 Elijah Newren <newren gmail com> - - * NEWS: 2.15.21 release - -2006-08-07 Elijah Newren <newren gmail com> - - Add a constrain_titlebar_visible constraint; should fix both bug - 333328 and bug 345522. Not perfect (minor annoying snap pulling - windows back onscreen, plus an ugly hack almost as bad as the old - one), but tarballs are due in less than half an hour. ;-) - - * src/boxes.[ch] (meta_rectangle_overlaps_with_region): - new function - - * src/constraints.c (constrain_titlebar_visible): new function, - (enum ConstraintPriority, array all_constraints, - update_onscreen_requirements): various small changes to - accomodate the new function - - * src/edge-resistance.c: remove the infinite edge resistance, - which was a big hack of a way to workaround the lack of a - titlebar_visible constraint - - * src/window.[ch] (MetaWindow): new require_titlebar_visible - bitfield, (meta_window_new_with_attrs): initialized here - -2006-08-07 Elijah Newren <newren gmail com> - - * src/frames.c (meta_frames_button_press_event): Patch from Chris - Ball to not minimize in response to double clicks on the titlebar - when minimiziation should not be allowed. #347377 - -2006-08-07 Elijah Newren <newren gmail com> - - Patch from Björn Lindqvist to fix button lighting with dragged - clicks. #321474. - - * src/frames.c (meta_frames_button_press_event): update the - prelit_control, (meta_frames_button_release_event): some code - refactoring to simplify things a bit, and make sure to update the - prelit_control - -2006-08-07 Elijah Newren <newren gmail com> - - * src/keybindings.c (process_keyboard_move_grab): Patch from - Thomas Andersen to return the window to maximized state if the - window was "shaken loose" from maximized state during a resize but - the resize is later aborted. #346719. - -2006-08-07 Elijah Newren <newren gmail com> - - Patch from Vytautas Liuolia to react to _NET_STARTUP_ID changes, - as proposed for the new startup-notification/EWMH spec. #347515 - - * src/window-props.c (reload_net_startup_id): be sure to act on - the new id instead of just recording it - - * src/window.[ch] (window_activate, meta_window_activate, - meta_window_activate_with_workspace, meta_window_client_message): - change window_activate() to take a workspace parameter instead of - hardcoding to the current workspace, add - meta_window_activate_with_workspace() function needed by - reload_net_startup_id(). - -2006-08-07 Thomas Thurman <thomas@thurman.org.uk> - - * src/frames.h: add new MetaButtonSpace struct; use it for - close_rect, max_rect, min_rect and menu_rect. (#97703) - - * src/frames.c (control_rect, get_control): modify to support - the new fields in MetaButtonSpace. - - * src/theme.c (meta_frame_layout_get_borders, rect_for_function, - meta_frame_layout_calc_geometry, button_rect): add support for - the new fields in MetaButtonSpace. - -2006-08-07 Elijah Newren <newren gmail com> - - * src/screen.c (meta_screen_resize_func): patch from Dmitry - Timoshkov to make sure window features get recalculated when the - screen is resized via XRandR. Part of #346927. - -2006-08-04 Elijah Newren <newren gmail com> - - Patch from Dmitry Timoshkov to fix the heuristic for determining - if windows can be made fullscreen (needed for WINE and possible - also some legacy applications). Part of #346927. - - * src/window.c (recalc_window_features): ignore window decoration - when checking size for determing whether an unresizable window - should be allowed ot be considered for fullscreening - -2006-07-31 Björn Lindqvist <bjourne@gmail.com> - - * src/window.c: Make it so maximized windows do not have rounded - corners. #336850. - -2006-07-30 Jens Granseuer <jensgr@gmx.net> - - * src/tabpopup.c: Fix another C89 vs. C99 issue. #347621. - -2006-07-26 Vincent Untz <vuntz@gnome.org> - - * src/update-from-egg.sh: also kill this - -2006-07-25 Vincent Untz <vuntz@gnome.org> - - * src/Makefile.am, ui.c: Kill usage of libegg. #348633. - -2006-07-24 Thomas Thurman <thomas@thurman.org.uk> - - * configure.in: post-release version bump to 2.15.21 - -2006-07-24 Thomas Thurman <thomas@thurman.org.uk> - - * NEWS: 2.15.13 release - -2006-07-24 Björn Lindqvist <bjourne@gmail.com> - - * src/display.c (meta_display_grab_window_buttons): Grab - Alt+Shift+Button1 as well to partially fix operation ordering - issues when trying to snap-move windows. Part of #112478. - -2006-07-21 Thomas Thurman <thomas@thurman.org.uk> - - * ui.[ch] (filter_func): Avoid a case where a struct's - fields might be updated after it was freed. #348067. - -2006-07-10 Elijah Newren <newren gmail com> - - * configure.in: post-release version bump to 2.15.13 - -2006-07-10 Elijah Newren <newren gmail com> - - * NEWS: 2.15.8 release - -2006-06-12 Elijah Newren <newren gmail com> - - * configure.in: post-release version bump to 2.15.8 - -2006-06-12 Elijah Newren <newren gmail com> - - * NEWS: 2.15.5 release - -2006-06-10 Elijah Newren <newren gmail com> - - Patch from Aidan Delaney to tidy tabpopup.c by factoring out - tab_entry_new(). #166890. - - * src/tabpopup.c (tab_entry_new): new function, - (meta_ui_tab_popup_new): use tab_entry_new() to remove a big chunk - of code, plus a few other small cleanups. - -Tue Jun 6 12:46:42 2006 Søren Sandmann <sandmann@redhat.com> - - * configure.in (GETTEXT_PACKAGE): Bunp intltool requirement to - 0.35.0. - -2006-05-29 Elijah Newren <newren gmail com> - - * HACKING: Slightly more detailed instructions on setting up a - build environment to mention relevant development tools in - addition to the needed development libraries. - -Fri May 26 16:48:29 2006 Søren Sandmann <sandmann@redhat.com> - - * src/effects.c (meta_effect_run_unminimize): Run an unminimize effect - - * src/window.c (meta_window_unminimize): Store a "was_minimized" - boolean in the window. - - * src/window.c (meta_window_show): If the window was minimized, - run an unminimize animation. - - * src/c-window.c (meta_comp_window_run_unminimize): Add an - unminimize animation, running the minimize one in reverse. - -Fri May 26 14:55:07 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.c (meta_comp_window_run_focus): Rename from - _bounce() to _focus(). - -2006-05-26 Elijah Newren <newren gmail com> - - * src/display.c (meta_display_close): Fix a crash on exit/logout - from assuming a compositor would always exist - -2006-05-25 Elijah Newren <newren gmail com> - - * src/place.h: - * src/common.h: - Remove MetaWindowEdgePosition enum that isn't used anymore - -Thu May 25 15:56:43 2006 Søren Sandmann <sandmann@redhat.com> - - * src/effects.h (struct MetaEffect): Move duplicated window field - outside the union - - * src/compositor.c: delete duplicated code to get at the window. - -Thu May 25 15:17:29 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.c: Fix compilation in non-compositor case, by - moving the stack functions into the HAVE_COMPOSITOR defines. - -Thu May 25 15:11:58 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.h: Add a destroy notifier to the window. - - * src/c-screen.c (on_window_destroy): New function. - - * src/c-screen.c (meta_comp_screen_add_window): Use the destroy - notifier here. - - * src/c-window.c (generate_phases): New function. Simplify the - minimize animation a lot by generating all the rectangle - information into an array, then processing that. - -2006-05-25 Adam Jackson <ajax@freedesktop.org> - - * src/c-window.c: - * src/c-window.h: - * src/compositor.c: - * src/compositor.h: - * src/effects.c: - * src/effects.h: - * src/spring-model.c: - * src/window.c: - Bounce on window focus. - -Wed May 24 22:15:01 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (do_effect): Make sure windows are kept on top - of the panel during minimize. - -Wed May 24 21:17:59 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (do_effect): Shrink the window instead of - explode it. - - * src/compositor.c (do_effect): don't read the frame if it is - NULL. - - * src/c-window.c (meta_comp_window_run_minimize): Resurrect the - shrinking minimize animation. - - * src/c-window.c (meta_comp_window_fade_in): Make dialogs 90% - translucent. - - * src/c-window.c (update_fade): End at end_fade, not 1.0. - -Wed May 24 19:15:45 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.c (cancel_fade): Add a fade-in animation when - windows are mapped. - -Wed May 24 16:37:11 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.c (private_metacity_window): New function - - * src/c-window.c (meta_comp_window_refresh_attrs): Map metacity's - own windows directly. - -Wed May 24 16:35:54 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.c (private_metacity_window): - -Wed May 24 14:36:42 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.c (meta_comp_window_{freeze,thaw}_stack: Add a - stack-freeze feature to CWindow. - - * src/c-screen.c (meta_comp_screen_restack): Don't restack if the - window is frozen. - -Wed May 24 13:09:49 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.c: Fix compilation in the non-composited case. - -Wed May 24 12:57:32 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.c (meta_comp_window_free): return TRUE when the - window is actually freed. - - * src/compositor.c (do_effect): Disable updating before exploding - the window. - - * src/c-window.c: Make MetaCompWindow refcounted. - - * src/c-window.[ch]: New functions meta_comp_window_{show,hide} - - * src/c-screen.c (meta_comp_screen_unmap): Call - meta_comp_window_hide() instead of directly setting the viewable - status of the node. - - * src/c-screen.c (meta_comp_screen_remove_window): Only remove the - window when it is actually freed. - -Wed May 24 12:45:21 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c: Delete unused meta_comp_screen_hide_window(). - -2006-05-23 Adam Jackson <ajax@freedesktop.org> - - * src/c-window.c: - * src/c-window.h: - * src/compositor.c: - * src/effects.c: - * src/effects.h: - * src/window.c: - Move shrink effect code from compositor.c to c-window.c. Stubs for - restore effect. Notes in various places for where to hook in - other effects. - -Tue May 23 16:36:04 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (do_effect): Also use explode when windows close. - - * src/c-window.c (meta_comp_window_explode): Add refcounting to - comp window, and use it in the explosion effect - - * src/effects.h (struct MetaEffect): Add new MetaCloseEffect. - - * src/display.c (event_callback): Run it from the UnmapNotify - event handler. - -Tue May 23 15:23:58 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.c (send_sync_request): New function to send a sync - request to newly mapped windows. - (on_request_alarm): Show the window here. - -2006-05-23 Adam Jackson <ajax@freedesktop.org> - - * src/effects.h: - Add more effect tokens. - -Mon May 22 17:35:52 2006 Søren Sandmann <sandmann@redhat.com> - - * src/effects.[ch]: Beginning of new layer that abstracts - transition effects. - - New functions: - (meta_push_effect_handler): Install an effect handler - (meta_pop_effect_handler): Remove last effect handler - (meta_effect_run_minimize): Create a minimize effect and pass it - to the handler. - (meta_effect_end): Called by handler when the effect is finished. - - * src/compositor.c: Move explosion code form there to src/c-window.c. - - * src/c-screen.c: Delete explosion related code. - -2006-05-22 Björn Lindqvist <bjourne@gmail.com> - - * common.h (enum MetaCursor): - * display.c (meta_display_create_x_cursor): Make mouse cursor when - moving windows become a hand. Fixes #337376. - -2006-05-19 Björn Lindqvist <bjourne@gmail.com> - - * frames.c: Fix a logic bug so that the whole titlebar becomes - sensitive to mouse clicks. Fixes #336320. - -2006-05-18 Björn Lindqvist <bjourne@gmail.com> - - * resizepopup.c: Remove the unused attributes resize_gravity, - width_inc, height_inc, min_width, min_height, frame_left, - frame_right, frame_top, frame_bottom, tick_origin_x, tick_origin_y - from the MetaResizePopup struct. Delete all code that references - those attributes. - -2006-05-15 Elijah Newren <newren gmail com> - - * configure.in: post-release version bump to 2.15.5 - -2006-05-15 Elijah Newren <newren gmail com> - - * NEWS: 2.15.3 release - -2006-05-15 Elijah Newren <newren gmail com> - - Revert the accessibility module loading workaround from Gnome - 2.6, since gtk+ has long since fixed this for us. #123372. - - * src/Makefile.am: remove METACITY_LIBDIR define - - * src/main.c (find_accessibility_module, - accessibility_invoke_module, accessibility_invoke, main): remove - the first three of these functions and all calls to them - - * src/tabpopup.c (meta_ui_tab_popup_new): not sure if this part of - 120025 needed to be reverted but doing the reversion, if wrong, is - the best way to get someone from the accessibility team to scream, - er, I mean comment. ;-) - -2006-05-15 Elijah Newren <newren gmail com> - - * src/screen.c (reload_xinerama_infos): Patch from - jylefort@FreeBSD.org to prevent a crash when changing resolution. - Fixes #340847. - -2006-05-15 Björn Lindqvist <bjourne@gmail.com> - - * places.[ch] (intcmp, window_get_edges, - get_windows_showing_on_same_screen, get_vertical_edges, - get_horizontal_edges, meta_window_find_next_vertical_edge, - meta_window_find_next_horizontal_edge, - meta_window_find_nearest_vertical_edge, - meta_window_find_nearest_horizontal_edge): Remove the preceeding - functions as they are all obsoleted by the new edge-resistance - stuff. Fixes #341561. - -2006-05-15 Paolo Borelli <pborelli@katamail.com> - - * src/prefs.c (update_binding): plug a small leak. - -2006-05-12 Elijah Newren <newren gmail com> - - * configure.in: I don't think we want a config file for the - no-gconf case; embedded people would prefer hard-coding things - into the binary - (http://mail.gnome.org/archives/metacity-devel-list/2006-May/msg00010.html) - -2006-04-25 Elijah Newren <newren gmail com> - - * HACKING: Clarify that gnome-common is needed now that autogen.sh - has been rewritten to use gnome-autogen.sh - -Fri May 5 12:50:58 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.c (has_counter): Some experimental code to handle - sync counter notifications on a window. - - * src/c-screen.c (meta_comp_screen_add_window): Pass a MetaDisplay - -2006-04-25 Elijah Newren <newren gmail com> - - Clear _NET_WM_VISIBLE_NAME (and the ICON_ equivalent) when no - longer being used. Fixes #330671. - - * src/window.[ch] (struct MetaWindow): new - using_net_wm_visible_name and using_net_wm_visible_icon_name bits, - (meta_window_new_with_attrs): initialize these new bits to false - - * src/window-props.c (set_title_text, set_window_title, set_icon_title): - if the _NET_WM_VISIBLE_(ICON_)NAME property was previously set but - doesn't need to be this time, make sure to clear it - -2006-04-25 Elijah Newren <newren gmail com> - - * rationales.txt: add three new tracker bugs - -Thu May 4 13:30:04 2006 Søren Sandmann <sandmann@redhat.com> - - * src/ui.h: Delete unused META_PRIORITY_COMPOSITE - - * src/ui.c: Delete argument from meta_ui_get_display(). - - * src/c-window.c: Remove the xid->window hashtable and associated - code. - - * src/c-screen.[ch]: Rename MetaScreenInfo to MetaCompScreen. Put the - xid->windows table here instaed of as a static variable. Also make - sure that CompWindows are freed when the screen is unredirected. - - * src/display.c: Delete non USE_GDK_DISPLAY case, as it didn't - work and hasn't been compiled for a long time. - - * src/display.[ch] (meta_display_open): Remove argument as it was - always NULL (and couldn't possibly be anything else in the - USE_GDK_DISPLAY case). - -Tue May 2 17:12:54 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-window.[ch]: New files - - * src/c-screen.c: Move WindowInfo struct to new c-window.[ch] - files. Delete various bits of obsolete, commented-out code. - -Fri Apr 28 12:53:23 2006 Søren Sandmann <sandmann@redhat.com> - - * src/core.c (get_window): New function. - * src/core.c: Use get_window() instead of cutted-and-pasted code - all over the place. - -2006-04-25 Elijah Newren <newren gmail com> - - * configure.in: post-release version bump to 2.15.3 - -2006-04-25 Elijah Newren <newren gmail com> - - * NEWS: 2.15.2 release - -2006-04-25 Elijah Newren <newren gmail com> - - * autogen.sh: Nuke the old version, copy one from gcalctool that - uses gnome-autogen.sh. Seems to fix the - translations-aren't-included-in-the-tarball problem. Fix from - Rodney in IRC. - -2006-04-25 Elijah Newren <newren gmail com> - - * configure.in: post-release version bump to 2.15.2 - -2006-04-25 Elijah Newren <newren gmail com> - - * NEWS: 2.15.1 release - * configure.in: belated post-release version bump to 2.15.1 - * src/Makefile.am: Include boxes.h so that control-center won't - fail to build #339708. - -2006-04-24 Elijah Newren <newren gmail com> - - * NEWS: 2.15.0 release - -2006-04-20 Brian Pepple <bdpepple@gmail.com> - - #337951. - - * po/LINGUAS: New file listing all supported languages. - - * configure.in: Use po/LINGUAS instead of including all languages - directly in this file. See the wiki for more information: - http://live.gnome.org/GnomeGoals/PoLinguas. - -2006-04-19 Thomas Andersen <phomes@gmail.com> - - * src/window-props.c (reload_transient_for): warn and ignore if - transient_for is set to a non-top-level window. Fixes #335524. - -2006-04-19 Björn Lindqvist <bjourne@gmail.com> - - * src/frames.c (struct CachedPixels, meta_frames_destroy, - invalidate_cache, generate_pixmap, populate_cache, - cached_pixels_draw, meta_frames_expose_event, - meta_frames_paint_to_drawable): - - Replace while loops iterating over sequences with for loops. Also, - replace the attributes in the CachedPixels struct with a list of - four CachedFramePiece:s, this allows iteration over the four - pixmaps instead of treating each one separately. Fixes #338359. - -2006-04-18 Björn Lindqvist <bjourne@gmail.com> - - * makefile.am: Add boxes.{c,h} to libmetacity_private - * src/theme-parser.c (check_expression): - * src/theme-viewer.c (run_position_expression_tests): - Use meta_rect (). - - * src/theme.c: Replace while loops iterating over sequences with - for loops. - - * src/theme.c, src/theme.h (struct _MetaPositionExprEnv, - meta_draw_op_draw, meta_draw_op_list_draw, - meta_theme_draw_menu_icon): Use MetaRectangles in function - prototypes instead of x, y, with, height ints where applicable. - -2006-04-18 Kjartan Maraas <kmaraas@gnome.org> - - * configure.in: Remove obsolete entry for no_NO - * po/no.po: And the translation. - -2004-04-17 Thomas Thurman <thomas@thurman.org.uk> - - * keybindings.c (count_bindings, rebuild_binding_table): - * prefs.c (change_notify, screen_bindings, - window_bindings, init_bindings, update_binding, - find_and_update_list_binding, update_list_binding, - meta_prefs_get_window_binding): Allow any keybinding pref - to be specified either with <foo>, a string, or <foo>_list, - a list of strings, or both. Fixes #164831. - -2006-04-16 Elijah Newren <newren gmail com> - - Patch from Dan Sanders to fix #334899. - - * window.c (meta_window_new_with_attrs): Unminimize ancestors of - new windows when mapped; this prevents e.g. confirmation windows - from causing applications to appear locked when closing via the - window list. - -2006-04-15 Elijah Newren <newren gmail com> - - Patch from Dan Sanders to fix #335076. - - * src/core.c (meta_core_maximize, meta_core_toggle_maximize, - meta_core_unmaximize): - * src/window.c (meta_window_client_message): - Raise windows on maximize/unmaximize. - -2006-04-15 Elijah Newren <newren gmail com> - - * src/display.h: Patch from Andy Morum to fix the build with - --disable-xsync. #336605 - -2006-04-14 Elijah Newren <newren gmail com> - - * HACKING: Include instructions on setting up a minimal - building/testing environment - -2006-04-14 Thomas Thurman <thomas@thurman.org.uk> - - Add a tabbing function, bound to alt-f6 by default, to cycle - through the windows of the current application. Fixes #94682. - - * src/common.h: two new MetaGrabOpts values for group switching - * src/display.c (ping_data_free, meta_display_in_grab_op, - IN_TAB_CHAIN): adapt to new MetaGrabOpts - * src/display.h: new enum value for MetaTabList for group switching - * src/keybindings.c (meta_display_process_key_event): - adapt to new MetaGrabOpts - (process_tab_grab): adapt to new MetaGrabOpts, and use switch - statement for cancelling instead of if statement - * src/metacity.schemas.in: new keybindings - * src/prefs.c, src/prefs.h: handle new keybindings - * src/window.h: define META_WINDOW_IN_GROUP_TAB_CHAIN macro - -2006-04-14 Elijah Newren <newren gmail com> - - * HACKING: Include reasons why gdk/gtk.h and core includes like - display.h/window.h must be kept separate. Taken from a private - email from Havoc. - -2006-04-13 Alejandro Andres <fuzzy.alej@gmail.com> - - * README: Fixed broken links. #333303 - -Thu Apr 13 12:23:28 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (meta_screen_info_add_window): Check for both - POPUP and DROPDOWN. - -2006-04-13 Björn Lindqvist <bjourne@gmail.com> - - * src/async-getprop.c, src/async-getprop.h - (async_get_property_handler, ag_task_get_reply_and_free): - * src/testasyncgetprop.c (try_get_reply, run_speed_comparison): - Change unsigned chars to chars. - - * src/display.h (struct MetaDisplay): - * src/keybindings.c (reload_modmap): - Change unsigned ints to ints. - - * src/screen.c (set_workspace_names) - * src/stack.c (meta_stack_sync_to_server): - * src/xprops.c (utf8_string_from_results, utf8_list_from_results, - class_hint_from_results, meta_prop_get_values): - Introduce casts. - - Add a number of casts and change signedness on a number of - variables so that Metacity compiles with many fewer - warnings. Fixes #336032. - -2006-04-12 Elijah Newren <newren gmail com> - - Patch from Ron Yorston to add a focus_new_windows option. Default - is 'smart' (focus by default but normal focus-stealing-prevention - can kick in); 'strict' is current other choice (like 'smart' - except that programs launched by the terminal will not be - focused). Fixes remainder of #326159. Should also close #152004 - and a bunch of others. - - * src/common.h: - Add a MetaFocusNewWindows enum giving the current types allowed - - * src/display.h: - Update docs on allow_terminal_deactivation to note that it is only - relevant when focus_new_windows is 'strict' - - * src/metacity.schemas.in: add the new gconf key and explanation - - * src/prefs.[ch] (#define KEY_FOCUS_NEW_WINDOWS, static gboolean - focus_new_windows, update_focus_new_windows, meta_prefs_init, - change_notify, meta_prefs_get_focus_new_windows, - meta_preference_to_string): - Add all the normal preference handling stuff for this new - focus-new-windows option. - - * src/window.c (window_state_on_map, meta_window_set_user_time): - Don't focus windows launched from a terminal - -Mon Apr 10 16:44:51 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (is_menu): Check if the window is a menu and make - it 90% opaque in that case. - - * src/c-screen.c (claim_selection): Handle CM_Sn selection - properly. - - * src/c-screen.c: Remove debug spew - - * src/screen.c (meta_screen_composite_all_windows): Remove debug spew - -2006-04-10 Björn Lindqvist <bjourne@gmail.com> - - * display.c (meta_display_open, event_callback): - * ui.c (meta_ui_get_double_click_timeout): - - Delete dead code that used to handle double click on the - titlebar. Remove the attributes last_button_time, - last_button_xwindow, last_button_num and is_double_click from - MetaDisplay and the functions meta_ui_get_double_click_timeout() - and meta_display_is_double_click() from their respective - files. Fixes #337507. - -2006-03-27 Gora Mohanty <gmohanty@cvs.gnome.org> - - * src/metacity.schemas.in: - * src/theme.c: - Changes strings to make them more readable, and more translatable. - Fixes #335720. - -2006-04-02 Elijah Newren <newren gmail com> - - Fix constraints bug causing negative width windows and crashes. - #336651 - - * src/constraints.c (constrain_partially_onscreen): Don't - accidentally shove & resize the window by requiring more pixels to - be onscreen than the size of the window. - -Fri Mar 31 16:44:56 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (meta_screen_info_unredirect): Release the GL - window here. Disconect from the magnifier, not the stacker. - -Fri Mar 31 12:24:26 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (meta_screen_info_redirect): Only use magnifier - when USE_MAGNIFIER is set. - - * src/compositor.c (meta_compositor_free_window): Only wobble when - USE_WOBBLE is set. - -Fri Mar 31 12:13:21 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (meta_screen_info_redirect): Don't hardcode - screen size. - -Thu Mar 30 17:01:12 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (struct MetaCompositor): Fix the memory - corruption in a better way. - -Thu Mar 30 16:38:35 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (meta_compositor_begin_move): Fix an illegal write. - -Thu Mar 30 16:13:52 2006 Søren Sandmann <sandmann@redhat.com> - - * composite.c: Turn wobbling back on Add new explosion effect. - -2006-03-29 Elijah Newren <newren gmail com> - - Fix grouping in the presence of ancestors; caught by Björn. - #336184 - - * src/group.c (meta_window_compute_group): Use new - meta_window_find_root_ancestor() function to get ancestor; for the - computed group, use the ancestor's group instead of the ancestor - itself - - * src/window.[ch] (meta_window_find_root_ancestor, - meta_window_raise): split meta_window_find_root_ancestor() - functionality of meta_window_raise() and make it available - elsewhere - -2006-03-29 Elijah Newren <newren gmail com> - - * rationales.txt: Add bugs about pointer warping; update - raise-on-click ones. - -2006-03-29 Thomas Thurman <thomas@thurman.org.uk> - - Abstract out the functions for setting/unsetting demands attention - hint and avoid doing it when the window isn't obscured. Fixes the - remainder of #305882. - - * src/window.c, src/window.h (meta_window_set_demands_attention, - meta_window_unset_demands_attention): new functions to mark a - window as needing or not needing the user's attention - * src/window.c (meta_window_show, window_activate, - meta_window_focus, meta_window_configure_request, - meta_window_client_message): use the new set/unset - demands attention functions. - -2006-03-29 Björn Lindqvist <bjourne@gmail.com> - - * src/resizepopup.c: - * src/resizepopup.h: - * src/window.c (meta_window_refresh_resize_popup): - Aggregate the x, y, width and height attributes of MetaResizePopup - to one MetaRectangle rect attribute and update code using the - MetaResizePopup struct. Fixes #335177. - -2006-03-28 Elijah Newren <newren gmail com> - - * MAINTAINERS: New file. #335026. ;-) - -Tue Mar 28 09:57:26 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (meta_screen_info_add_window): Also check for overlay_window. - - * src/c-screen.c (meta_screen_info_redirect): Trap errors out of - unredirect(). - -2006-03-25 Thomas Thurman <thomas@thurman.org.uk> - - * src/window.c, src/window.h (update_net_wm_state, - update_mwm_hints, update_wm_class, update_transient_for): - deleted and moved into window-props.c - (meta_window_new_with_attrs): added constructing field - and four new initial properties (as above) - (meta_window_recalc_features, - meta_window_recalc_window_type): new functions - - * src/window-props.c (init_net_wm_state, reload_net_wm_state - init_mwm_hints, reload_mwm_hints, init_wm_class, - reload_mwm_class, init_transient_for, reload_transient_for): - new functions, moved in from window.c - - (meta_display_init_window_prop_hooks): initialise new properties - - Closes #309567. - -2006-03-25 Paolo Borelli <pborelli@katamail.com> - - * src/prefs.c: use g_str_has_prefix instead of a local copy - of the function. - -2006-03-16 Ray Strode <rstrode@redhat.com> - - Add patch from Elijah Newren to fix type - for compositing_manager schema entry (bug 335901) - - * src/metacity.schemas.in: Change type from "boolean" to "bool" - and default value from "FALSE" to "false" - -Wed Mar 22 13:16:48 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (meta_compositor_remove_window): Actually - remove the window. - - * src/c-screen.c (meta_screen_info_remove_window): Only remove - node if non-NULL - -Wed Mar 22 10:33:21 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (meta_screen_info_redirect): Put a square below - the desktop stack. - -Mon Mar 20 11:50:44 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (meta_screen_info_redirect): Put the desktop into - a magnifier. - - * src/c-screen.c (struct MetaScreenInfo): Add a CmMagnifier - - * src/c-screen.c (meta_screen_info_redirect): Move some of the gl - window related stuff here. - -2006-03-16 Soren Sandmann (sandmann@daimi.au.dk) - - * src/c-screen.c (meta_screen_info_set_target_rect): Put inside - COMPOSIT_EXTENSIONS - -2006-03-03 Thomas Thurman <thomas@thurman.org.uk> - - Always set _NET_WM_STATE when a window is shown or - hidden, even if it wasn't mapped. Fixes #315142. - - * src/window.c (meta_window_hide, meta_window_show): - call set_net_wm_state unconditionally - -2006-03-16 Elijah Newren <newren gmail com> - - Add debugging information for edge resistance - - * src/edge-resistance.c (cache_edges): print out the edges that - are being cached if in verbose mode, - (meta_window_edge_resistance_for_move, - meta_window_edge_resistance_for_resize): if edge resistance kicked - in then print out a message about it - - * src/util.c: - * src/util.h: - Add META_DEBUG_EDGE_RESISTANCE to MetaDebugTopic enum list - -Thu Mar 16 14:55:18 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (struct WindowInfo): Maintain the size of the - window. - -Wed Mar 15 16:30:09 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (set_geometry): Use set_target_rect() instead - of set_size(). - - * src/c-screen.c: Add set_target_rect() as a way of scaling windows. - - * src/window.c (meta_window_handle_mouse_grab_op_event): Turn - updates on after a button release. - - * src/window.c (meta_window_move_resize_internal): Fix - indentation. - -Wed Mar 15 11:34:54 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (meta_screen_info_add_window): Use unset_patch() - instead of unset_geometry(). - -Tue Mar 14 11:57:46 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c: Comment out wobbling - - * src/compositor.c (blow_up): remove this function - - * src/compositor.c (process_configure_notify): Uncomment - set_size(). - - * src/c-screen.c (meta_screen_info_set_updates): When updates are - true, set all the properties such as size and shape. - - * src/c-screen.c (meta_screen_info_add_window): Create a special - WindowInfo structure for each window. - - * src/c-screen.c (meta_screen_info_set_size): Set size and output - shape of the drawable node. - -2006-03-13 Elijah Newren <newren gmail com> - - * README: - * configure.in: - Update to reflect that we're now targetting 2.15 development. - -2006-03-12 Thomas Thurman <thomas@thurman.org.uk> - - * src/window-props.c (set_title_text): Mark a particular - string for translation. #334332. - -2006-03-06 Ryan Lortie <desrt@desrt.ca> - - * src/window.c (meta_window_free): Only unmaximise window before - freeing if the window is actually maximised. #333563. - -Fri Mar 3 15:31:04 2006 Søren Sandmann <sandmann@redhat.com> - - * src/c-screen.c (meta_screen_info_new): Update for libcm API - change. - -Wed Mar 3 13:25:03 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c, src/c-screen.[ch]: Split the ScreenInfo data - structure into separate, new files c-screen.[ch]. - - * src/errors.c (x_error_handler): Forward foreign errors to - foreign displays. - - * src/errors.c (meta_errors_register_foreign_display): Implement - this function - - * src/errors.h: Add new meta_errors_register_foreign_display() - -Tue Feb 28 14:49:23 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c: Put the windows in a stacker rather than - do the traversing outselves. - -2006-02-27 Elijah Newren <newren gmail com> - - Patch from Thomas Thurman to prevent setting cycle_windows to - keybindings that won't work. #329676 - - * src/prefs.c (update_binding): - Make sure that bindings which require a modifier key are set to a - keybinding with one or else that the binding is reverted. - - * src/ui.[ch] (meta_ui_accelerator_name): - New function - -2006-02-27 Elijah Newren <newren gmail com> - - Patch from Thomas Thurman to work around buggy application - grouping with transient windows. #328211 - - * src/group.c (meta_window_compute_group): - Put transients in the same group with their parent, always. - - * src/window.c (update_transient_for): - Update group too - -2006-02-27 Elijah Newren <newren gmail com> - - * configure.in: - Patch from Sylvain Bertrand to fix build issues with library - search order. #330695. - -Sat Feb 25 14:50:17 2006 Søren Sandmann <sandmann@redhat.com> - - * src/window.c: Remove include of flash.h - -Sat Feb 25 11:46:14 2006 Søren Sandmann <sandmann@redhat.com> - - * src/display.c (meta_display_begin_grab_op): Call - meta_compositor_begin_move if there is a compositor - - * src/compositor.c (meta_compositor_begin/update/end_move): - Implement those functions. - - * src/spring-model.[ch]: New files - -Thu Feb 23 15:40:52 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (meta_compositor_manage_screen): Don't attempt - to manage the screen if it already is managed. - - * src/compositor.c (meta_compositor_unmanage_screen): Synchronize - the display. - -2006-02-19 Thomas Thurman <thomas thurman org uk> - - Removed "move to another workspace" menu when there are - exactly two workspaces. Fixes #151183. - - * src/menu.c (meta_window_menu_new): clear - META_MENU_OP_WORKSPACES bit when n_workspaces==2 - -Fri Feb 17 11:56:35 2006 Søren Sandmann <sandmann@redhat.com> - - * src/screen.c (meta_screen_free): Only uncomposite the screen if - there is a compositor. - - * src/compositor.c (meta_compositor_new): Warn and fail if the - server doesn't have composite - -Thu Feb 16 18:57:48 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c: Fix the build when --enable-compositor is - there. - -Thu Feb 16 15:54:48 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c: Insert #ifdef's to make it build again - -Thu Feb 16 15:24:42 2006 Søren Sandmann <sandmann@redhat.com> - - * src/screen.c (meta_screen_composite_all_windows): New function. - - * src/prefs.[ch], src/metacity.schemas.in: Add new - compositing_manager key. - - * src/display.c (prefs_changed_callback): Handle - META_PREF_COMPOSITOR_MANAGER - - * src/display.c (event_callback): Only call - meta_compositor_process_event() if there is in fact a compositor. - - * src/display.c (enable/disable_compositor): Add code to - enable/disable compositor at runtime - -Wed Feb 15 18:42:03 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.[ch]: Add code to destroy compositor. Implement - unmanage_screen() functionality. - -Wed Feb 15 14:47:50 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (meta_compositor_unminimize): Add unused wobbly - unminimize animation by Kristian - - * src/compositor.c (meta_compositor_minimize): Add wobbly minimize - animation by Kristian. - - * src/compositor.c: Add support for turning updates on and off. - - * src/window.c (meta_window_move_resize_internal): Use - sync counter to make composited resizing tear free - -2006-02-14 Elijah Newren <newren gmail com> - - Patch from Jens Granseuer to fix more build issues with gcc 2.95. - #331166. - - * src/prefs.c (meta_prefs_init): - Remove C99 style variable initiailization - -2006-02-13 Elijah Newren <newren gmail com> - - * configure.in: post-release version bump to 2.13.144 - -2006-02-13 Elijah Newren <newren gmail com> - - * NEWS: 2.13.89 release - -2006-02-13 Elijah Newren <newren gmail com> - - * src/keybindings.c (process_tab_grab): - We had that prev_window code in multiple places and it was all - identical. Let's just stick it in one place to make the function - easier to read. - -2006-02-13 Thomas Thurman <thomas thurman org uk> - - * src/keybindings.c (process_tab_grab): - Allow alt-escape to cancel alt-tabbing, and vice versa. Fixes - #141425. - -2006-02-11 Thomas Thurman <thomas thurman org uk> - - Disable alt-f7 if a window can't be moved, and alt-f8 if it - can't be resized. Fixes #328920. - - * src/keybindings.c (handle_begin_move, handle_begin_resize): - check window->has_*_func before beginning operation - -2006-02-11 Elijah Newren <newren gmail com> - - Add a man page for metacity. Original version taken from Debian - (written by Thom May and Akira Tagoh) and updated by Luke Morton - and Philip O'Brien. Necessary auto-fu supplied by Philip O'Brien. - Fixes #321279. - -2006-02-11 Elijah Newren <newren gmail com> - - * src/stack.h (enum MetaStackLayer): - * src/stack.c (get_standalone_layer): - actually use META_LAYER_TOP but just manually make it equal to - META_LAYER_DOCK. Add a note point to the EWMH for why we do this. - #330717 - -2006-02-11 Elijah Newren <newren gmail com> - - * src/window.c (enum GnomeWinLayer): remove this legacy cruft that - we stopped using years ago - -2006-02-10 Thomas Thurman <thomas thurman org uk> - - Avoid a memory leak when checking which workspace(s) a window is - on. Fixes #322059. - - * src/workspace.h (struct MetaWorkspace): - * src/workspace.c (meta_workspace_new, meta_workspace_free): - added list_containing_self member to MetaWorkspace - - * src/window.c (meta_window_get_workspaces): use - window->workspace->list_containing_self instead of allocating (and - leaking) such a list on the fly. - -2006-02-09 Thomas Thurman <thomas thurman org uk> - - * src/testboxes.c (test_regions_okay, test_clamping_to_region): - add messages to explain that warnings are harmless - -Tue Feb 7 00:58:05 2006 Soeren Sandmann <sandmann@redhat.com> - - * src/compositor.c: Wrap fade code in #ifdef HAVE_COMPOSITE_EXTENSIONS - -Mon Feb 6 17:45:39 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c: New fancy minimize animation. Fade windows in - and out. - -2006-02-03 Thomas Thurman <thomas thurman org uk> - - * src/display.c (event_callback): produce warning when invalid - events with no timestamp are received, rather than failing an - assertion - -Thu Feb 2 17:58:22 2006 Søren Sandmann <sandmann@redhat.com> - - * compositor.c (process_map): update the pixmap. - (update) print out framerate. - (dump_stacking_order) new debug - function. - (meta_compositor_add_window) error trap fixes - (MiniInfo): Make the minimize animation fade out. - -2006-01-30 Elijah Newren <newren gmail.com> - - * configure.in: post-release version bump to 2.13.89 - -2006-01-30 Elijah Newren <newren gmail com> - - * NEWS: 2.13.55 release - -2006-01-30 Elijah Newren <newren gmail com> - - * src/display.[ch] (struct MetaDisplay), meta_display_open, - meta_display_set_input_focus_window, - meta_display_focus_the_no_focus_window): Track the active_screen, - (event_callback): If the mouse enters a window on a different - screen, activate the default window on the new screen. May need - to be modified for click-to-focus; we'll wait for feedback. Fixes - #319348. - -2006-01-23 Elijah Newren <newren gmail com> - - * src/display.c (meta_display_check_threshold_reached): change the - order of the ||'ed items in the if to avoid using an uninitialized - value - - * src/prefs.c (meta_prefs_init): fix a couple uninitialized value - problems - -2006-01-21 Elijah Newren <newren gmail com> - - Patch from Christian Kirbach to prevent a critical warning crasher - when switching themes. #327847. - - * src/theme.c (meta_theme_free): since themes are only constructed - as needed and may be NULL, check for that before freeing theme - hash tables - -2006-01-21 Elijah Newren <newren gmail com> - - * src/common.h (enum MetaActionDoubleClickTitlebar): - * src/frames.c (meta_frames_button_press_event): - * src/prefs.c (action_double_click_titlebar_from_string): - * src/metacity.schemas.in: - Patch from Dick Marinus to add a minimize - double-click-titlebar-action; slightly modified to also include a - none action. #300210. - -2006-01-20 Elijah Newren <newren gmail.com> - - * configure.in: post-release version bump to 2.13.55 - -2006-01-20 Elijah Newren <newren gmail com> - - * NEWS: 2.13.34 release - -2006-01-20 Elijah Newren <newren gmail com> - - * src/constraints.c (setup_constraint_info): fixed_directions is - only meant for explicit user interactions; disable it for - everything else. There are other bugs and improvements that could - be made with fixed_directions that I should be filing too, but at - least put a FIXME there for now--I'm so lame. Fixes #327822. - -2006-01-20 Elijah Newren <newren gmail com> - - Avoid flashing when closing a maximized window. Fixes #317254. - - * src/window.c (unmaximize_window_before_freeing): new function - that just fixes the net_wm_state and sends a configure_notify, - (meta_window_free): use unmaximize_window_before_freeing() instead - of meta_window_unmaximize() to avoid flicker - -2006-01-20 Elijah Newren <newren gmail com> - - Fix unitialized value problem when in raise-on-click mode. Søren, - #327572. - - * src/display.c (meta_display_check_threshold_reached): make - function be a no op if raise_on_click!=FALSE - - * src/display.h (struct MetaDisplay): point out that - grab_initial_[xy] and grab_threshold_movement_reached are only for - raise_on_click==FALSE mode. - -2006-01-20 Elijah Newren <newren gmail com> - - Patch from Søren to fix some reading-from-free'd-data errors. - #327575 - - * src/edge-resistance.c (meta_display_cleanup_edges): store the - edges in a hash table so that we can still read their values - within the loop from the other array they are stored in, then free - them all at the end. - -2006-01-20 Elijah Newren <newren gmail com> - - Fix various initialization and default issues, especially for - --disable-gconf. Make --disable-gconf actually work. #326661. - - * configure.in: Fix compilation with --disable-gconf - * src/metacity.schemas.in: Add a note that if any defaults are - changed in this file, src/prefs.c may need to be updated to - reflect the change - * src/prefs.c: set various static global vars to the right default - value, (meta_prefs_init): get the titlebar_font and current_theme - handled better when not using gconf, (struct MetaSimpleKeyMapping, - screen_string_bindings, window_string_bindings): helper vars to - allow some keybindings to work even without gconf, - (init_bindings): initialize bindings for the without-gconf case - too, (init_commands): make sure these are all NULL for the - non-gconf case so that we don't access random memory, - (init_workspace_names): just give these all a default name for the - non-gconf case, - (meta_prefs_change_workspace_name): actually change the name for - the non-gconf case too - -2006-01-20 Elijah Newren <newren gmail com> - - More careful error handling of values returned by GConf. Fixes - #326615. - - * src/prefs.c (get_bool): new helper function, (meta_prefs_init): - use get_bool to handle the case of a gconf key not existing, - (update_cursor_size): sanity check for sane values - -2006-01-20 Elijah Newren <newren gmail com> - - Prevent rapidly repeated visual bells from hanging metacity. - Fixes #322032. - - * src/display.h (struct MetaDisplay): add a last_bell_time field, - (XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS macro, - XERVER_TIME_IS_BEFORE macro): add parentheses around usage of - macro parameter - - * src/display.c (meta_display_open): initialize last_bell_time, - (event_callback): don't allow more than one bell per second - -2006-01-20 Elijah Newren <newren gmail com> - - * src/async-getprop.c: - * src/common.h: - * src/display.c: - * src/eggaccelerators.c: - * src/frames.c: - * src/gradient.c: - * src/iconcache.c: - * src/keybindings.c: - * src/metaaccellabel.c: - * src/place.c: - * src/prefs.c: - * src/preview-widget.c: - * src/screen.c: - * src/session.c: - * src/stack.c: - * src/tabpopup.c: - * src/theme-viewer.c: - * src/theme.c: - * src/window-props.c: - * src/window.c: - * src/workspace.c: - * src/tools/metacity-window-demo.c: - * src/wm-tester/test-gravity.c: - * src/wm-tester/test-resizing.c: - * src/wm-tester/test-size-hints.c: - Patch from Kjartan Maraas to fix a lot of tiny issues (unused - variable removal, making unused variables used again, correction - of types passed/declared for printf arguments, removal of unneeded - breaks and returns, dead code removal, dead code revival, renaming - to prevent shadowed variables, declaring unexported functions as - static) spotted by the intel compiler. #321439 - -2006-01-20 Elijah Newren <newren gmail com> - - Patch from Björn Lindqvist to fix #98340. - - * src/screen.c (meta_screen_ensure_tab_popup): Make sure an - outline border is shown even if a window frame's width is 0. - Also, correctly handle window outlines in showing desktop mode. - -Fri Jan 20 16:42:25 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c: Make minimize animation update again. - -Thu Jan 19 18:05:47 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (meta_compositor_manage_screen): - g_object_unref() rather than ws_region_unref(). - -Thu Jan 19 16:50:50 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c: Port to changes in libcm - -Tue Jan 17 17:25:29 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c: Port to changes in libcm. - -2006-01-16 Elijah Newren <newren gmail com> - - * src/window-props.c: manually define HOST_NAME_MAX if not already - defined to fix Solaris compilation issue. Caught by Damien - Carbery, patch from Havoc. #326745 - -2006-01-16 Elijah Newren <newren gmail.com> - - * configure.in: post-release version bump to 2.13.34 - -2006-01-16 Elijah Newren <newren gmail com> - - * NEWS: 2.13.21 release - -Mon Jan 16 11:55:20 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (meta_compositor_manage_screen): Really turn - off draw-in-a-loop. - -2006-01-15 Kyle Ambroff <kambroff@csus.edu> - - * src/workspace.c (focus_ancestor_or_mru_window): - If no valid window is found in the MRU list, then set focus to the - desktop window. (#317405) - -2006-01-15 Elijah Newren <newren gmail com> - - Fix accidental overzealous focus holding by the terminal - introduced by the original patch in bug 326159. Windows launched - from panel icons, the panel menu, or global keybindings should get - focus now. #326159. - - * src/display.c (meta_display_open, event_callback): - * src/display.h (struct MetaDisplay): - * src/keybindings.c (process_event): - * src/window.c (meta_window_set_user_time): - Add a new allow_terminal_deactivation field to MetaDisplay and use - it to track whether the user's last action was interaction with - the terminal or some outside action (global keybinding, clicking - on a dock, etc.) likely to launch a new window. - - * src/window.c (window_state_on_map): - Allow the focus switch from a terminal to something else if - allow_terminal_deactiviation is true. - - * src/keybindings.c (handle_panel_keybinding): - Remove some unneeded code. - -2006-01-15 Elijah Newren <newren gmail com> - - Patch from Jens Granseuer to fix more build issues with gcc 2.95. - #327050. - - * src/boxes.c (meta_rectangle_edge_cmp_ignore_type): - * src/window.c (meta_window_show): - Remove C99 style variable initiailization - -2006-01-14 Elijah Newren <newren gmail com> - - * src/window.c (__window_is_terminal): Don't dereference a NULL - string. Fixes #327013. - -2006-01-14 Elijah Newren <newren gmail com> - - * src/compositor.[ch]: fix compilation when - HAVE_COMPOSITE_EXTENSIONS is undefined. #326912 - -Fri Jan 13 16:37:26 2006 Søren Sandmann <sandmann@redhat.com> - - * src/compositor.c (update): Only update on damage events. - -2006-01-13 Elijah Newren <newren gmail com> - - Patch from Damien Carbery. Fixes #326746. - - * src/util.c: explicitly #include Xlib.h to fix a compilation - issue on Solaris. - -Fri Jan 13 14:40:19 2006 Søren Sandmann <sandmann@redhat.com> - - * configure.in: Add a dependency on libcm when building with - compositor. - - * src/window.c (meta_window_hide): Make this function static. - - * src/window.c (implement_showing): Use meta_compositor_minimize() - to do a weird minimize effect. - - * src/compositor.[ch]: Beginning of new GL based compositor. - - * src/screen.h (struct _MetaScreen): Add void pointer to - compositor data. - - * src/screen.c (meta_screen_new): Remove obsolete compositor - stuff; initialize compositor_data. Don't composite manage screen - out of this function. - - * src/errors.c (x_error_handler): Check that display is non-NULL - before using it. Add comment about how that can happen. - - * src/display.c (meta_display_{begin,end}_grab_op): Remove - explicity damage of windows. - - * src/display.c (meta_display_open): Composite manage all the - screens. - -2006-01-11 Elijah Newren <newren gmail com> - - * src/textboxes.c (test_area, test_intersect, test_equal, - test_overlap_funcs, test_basic_fitting, test_merge_regions, - test_regions_okay, test_region_fitting, test_clamping_to_region, - test_clipping_to_region, test_shoving_into_region, - test_find_onscreen_edges, - test_find_nonintersected_xinerama_edges, test_gravity_resize, - test_find_closest_point_to_line): - Replace __PRETTY_FUNCTION__ with G_STRFUNC, because lesser - compilers don't support the former. Caught by Damien Carbery, fix - suggested by Ray Strode. #326281. - -2006-01-10 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.13.21 - -2006-01-10 Elijah Newren <newren@gmail.com> - - * NEWS: 2.13.13 release - -2006-01-10 Elijah Newren <newren@gmail.com> - - * src/bell.c: - * src/boxes.c: - * src/boxes.h: - * src/constraints.c: - * src/core.c: - * src/display.c: - * src/display.h: - * src/edge-resistance.c: - * src/frames.c: - * src/keybindings.c: - * src/main.c: - * src/prefs.c: - * src/prefs.h: - * src/screen.c: - * src/screen.h: - * src/window.c: - * src/window.h: - Whoops, I forgot to keep my copyright info updated with my previous - commits as Havoc had asked me to do. Doing that now... - -2006-01-10 Elijah Newren <newren@gmail.com> - - Add a raise on click option, basically only because all the major - distros are patching it in anyway. See #326156. - - * src/metacity.schemas.in: add the new gconf key and explanation - - * src/prefs.[ch] (#define KEY_RAISE_ON_CLICK, static gboolean - raise_on_click, update_raise_on_click, meta_prefs_init, - change_notify, meta_prefs_get_raise_on_click, - meta_preference_to_string): - Add all the normal preference handling stuff for this new - raise-on-click option. - - * src/core.c (meta_core_show_window_menu): - * src/display.c (event_callback, meta_display_begin_grab_op): - * src/window.c (window_activate, meta_window_configure_request, ): - Only raise the window if in raise_on_click mode. - - * src/display.c (meta_display_begin_grab_op, - meta_display_end_grab_op, meta_display_check_threshold_reached): - * src/display.h (struct MetaDisplay): - * src/window.c (meta_window_handle_mouse_grab_op_event): - if not in raise-on-click mode only raise on button release if the - click didn't start a move or resize operation; needs a few extra - MetaDisplay fields to handle this - - * src/core.c (meta_core_user_lower_and_unfocus): - no need to do the MRU shuffling if not maintaining the stacking - order == MRU order invariant - - * src/frames.c (meta_frames_button_press_event): - * src/window.c (meta_window_begin_grab_op): - remove an unneeded window raising that is already handled elsewhere - -2006-01-10 Elijah Newren <newren@gmail.com> - - Don't "steal" focus from terminal windows for new window mappings - as the difference in usage between terminals and other apps seems - to suggest this difference in treatment. See #326159 for details, - feedback welcome. - - * src/window.[ch] (__window_is_terminal): New function, currently - an ugly hack and should be replaced by a new property set by - applications if the behavior works to our liking, - (window_state_on_map): don't transfer focus to new windows from - terminals unless the new window is a transient of the focused - terminal - - * src/keybindigns.c (handle_panel_keybinding): panel run dialog - keybinding should be counted as an explicit transfer of focus to - the new window, so override the - don't-transfer-focus-from-terminals in this case - -2006-01-09 Elijah Newren <newren@gmail.com> - - More thorough handling of source indication. Part of #326041. - - * src/window.c (window_activate): new function based off the old - meta_window_activate but which also takes source indication into - account, (meta_window_active): just call window_activate() with - the necessary source indication to get the behavior wanted, - (meta_window_client_message): check source indication too for - _net_active_window messages - - * src/window.h (enum MetaClientType): convenience enum for source - indication handling - -2006-01-09 Elijah Newren <newren@gmail.com> - - Make the taskbar less flash happy and fix up some related stacking - issues. #326035. - - * src/window.c (windows_overlap): new function, - (meta_window_show): if a window is denied focus but doesn't - overlap with the focus window there is no need to set the demands - attention hint nor stack that window below the focus window, - (meta_window_get_outer_rect): we're not modifying the window so - declare it to be const - -2006-01-09 Elijah Newren <newren@gmail.com> - - Fix window outline for minimized windows when using alt-esc. - #325092. - - * src/display.c (meta_display_begin_grab_op): Specify the showing - type of tabbing operation (Alt tab vs. alt-esc) in addition to the - listing type of tabbing operation (docks vs normal windows) to - meta_screen_ensure_tab_popup(). - - * src/display.h (enum MetaTabShowType): new convenience enum - - * src/screen.[ch] (meta_screen_ensure_tab_popup): require the - showing type be specified in addition to the tabbing type; put the - outline around the window instead of the icon when in alt-esc - mode. - -2006-01-09 Elijah Newren <newren@gmail.com> - - Fix reduced resources resize handling for windows with sizing or - resizing constraints. #325774. - - * src/display.c (meta_display_end_grab_op): Provide constraints.c - with the correct gravity information. - -2006-01-09 Elijah Newren <newren@gmail.com> - - Be more strict about what is considered a valid region with - partial struts. Fixes #322070. - - * src/boxes.[ch]: - (meta_rectangle_expand_region_conditionally): - new function behaving like meta_rectangle_expand_region() but - which only does so when the width and height of the rectangles - meet a certain threshold - - (replace_rect_with_list): - Remove a compiling warning - - * src/constraints.c: - (constrain_partially_onscreen): - provide minimum thresholds in each direction for the size of the - rectangles to avoid cases where only a single pixel thick layer of - a window might be showing - -2006-01-09 Elijah Newren <newren@gmail.com> - - * src/bell.c (meta_bell_notify_frame_destroy): Use the right - function to remove the timeout so that we don't crash if removed - at an inopportune time. Fixes #322031. - -2006-01-09 Elijah Newren <newren@gmail.com> - - * src/edge-resistance.c (apply_edge_resistance): Remove the - "pull-away" edge resistance. Fixes another of the zillions of - issues covered in #321905. - -2006-01-09 Elijah Newren <newren@gmail.com> - - * src/edge-resistance.c (apply_edge_resistance): Revert to the old - edge resistance behavior for keyboard movement/resizing based - resistance. Not only makes the code much simpler and shorter, but - also fixes another of the zillions of issues covered in #321905. - -2006-01-09 Elijah Newren <newren@gmail.com> - - * src/edge-resistance.c (apply_edge_resistance): Remove the - timeout resistance at screen/xinerama edges for the whiners. - Okay, it made sense. Fixes another of the zillions of issues - covered in #321905. - -2006-01-09 Elijah Newren <newren@gmail.com> - - * src/edge-resistance.c (apply_edge_resistance): Make extra - timeout edge resistance apply even if one edge already offscreen. - Fixes another of the zillions of issues covered in #321905. - -2006-01-09 Elijah Newren <newren@gmail.com> - - Allow edge resistance at both sides of a window and also when - edges don't overlap but are a single pixel away from doing so. - Fixes one of the zillions of issues covered in #321905. - - * src/boxes.[ch]: - (meta_rectangle_edges_align): - new function to handle the overlap or off by one determining - whether edge resistance should kick in for an edge. - - (meta_rectangle_edge_cmp_ignore_type): - new function to sort edges but ignore the type so that e.g. left & - right edges of windows can be used interchangeably. - - (meta_rectangle_edge_cmp): - now uses meta_rectangle_edge_cmp_ignore_type() to do most the work - and just adds an extra condition - - * src/edge-resistance.c: - (find_nearest_position): - use meta_rectangle_edges_align() now to determine whether the - edges align, - - (apply_edge_resistance, apply_edge_resistance_to_each_side): - have the edge resistance kick in if either the beginning or ending - positions would cause overlap in the given direction -- fixes an - uncommon but annoying corner case, - - (apply_edge_snapping, apply_edge_resistance_to_each_side, - meta_display_cleanup_edges, - stupid_sort_requiring_extra_pointer_dereference, cache_edges): - mix edges from both sides now - -2006-01-09 Elijah Newren <newren@gmail.com> - - Plug a few leaks. Fixes #309178. - - * src/main.c (main): remove an unneeded g_set_prgname() call, free - some strings allocated by the GOptions parsing - -2006-01-02 Elijah Newren <newren@gmail.com> - - Patch from Björn Lindqvist to fix a logic error. #322149. - - * src/window.c (update_resize): && should have been ||. - -2006-01-02 Elijah Newren <newren@gmail.com> - - Patch from Jens Granseuer to fix build with gcc 2.95. #322622. - - * src/boxes.c (meta_rectangle_region_to_string, - meta_rectangle_edge_list_to_string, fix_up_edges): - * src/constraints.c (meta_window_constrain, setup_constraint_info, - place_window_if_needed, constrain_maximization, - constrain_fullscreen, constrain_size_increments, - constrain_size_limits, constrain_aspect_ratio, - do_screen_and_xinerama_relative_constrai, - constrain_to_single_xinerama, constrain_fully_onscreen, - constrain_partially_onscreen): - * src/edge-resistance.c (find_nearest_position, - apply_edge_resistance, apply_edge_resistance_to_each_side): - * src/testboxes.c (test_clamping_to_region, - test_clipping_to_region, test_shoving_into_region): - * src/window.c (meta_window_new_with_attrs, - meta_window_apply_session_info, meta_window_resize, - meta_window_resize_with_gravity, meta_window_configure_request): - Remove C99 style variable initiailization - -2006-01-02 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.13.13 - -2006-01-02 Elijah Newren <newren@gmail.com> - - * NEWS: 2.13.8 release - -2005-12-27 Elijah Newren <newren@gmail.com> - - Make the workspace switcher work with dual-head (non-xinerama) - setups. Fixes #319423. - - * src/display.c (meta_display_open, event_callback, - meta_display_focus_the_no_focus_window): - * src/display.h (struct MetaDisplay, - meta_display_focus_the_no_focus_window): - * src/keybindings.c (primary_modifier_still_pressed): - * src/screen.c (meta_screen_new): - * src/screen.h (struct MetaScreen): - * src/window.c (meta_window_new_with_attrs, meta_window_show): - * src/workspace.c (meta_workspace_focus_default_window): - Replace display->no_focus_window with a no_focus_window for each - screen. - - * src/display.[ch] (meta_display_xwindow_is_a_no_focus_window, - event_callback): - * src/window.c (meta_window_new_with_attrs): - New utility function, meta_display_xwindow_is_a_no_focus_window(), - for checking if the given xwindow is a no_focus_window for one of - the screens. - -2005-12-27 Elijah Newren <newren@gmail.com> - - * src/tabpopup.c (meta_ui_tab_popup_new): since the title is going - to be treated as markup, escape it. Fixes #324846. - -2005-12-13 Kang Jeong-Hee <Keizi@mail.co.kr> - - * src/compositor.c: replace old call to width and height - of MetaScreen struct with rect.width and rect.height. - Now compile ok. - * src/delete.c: make an int variable into unsigned int. - Now compile warning has gone. - -2005-12-12 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.13.8 - -2005-12-12 Elijah Newren <newren@gmail.com> - - * NEWS: 2.13.5 release - -2005-12-12 Elijah Newren <newren@gmail.com> - - * src/window.c (update_net_frame_extents): make the debugging - message actually correspond to the code. Patch from Björn - Lindqvist. Fixes #322051. - -2005-11-29 Kjartan Maraas <kmaraas@gnome.org> - - * src/screen.h: Make the wireframe a bit slimmer. - Closes bug #320051. - -2005-11-24 Davyd Madeley <davyd@fugro-fsi.com.au> - - * src/window-props.c: display hostname in titlebar for remote X - clients. Closes bug #322202. - -2005-11-22 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.13.5 - -2005-11-22 Elijah Newren <newren@gmail.com> - - * NEWS: 2.13.3 release - -2005-11-22 Elijah Newren <newren@gmail.com> - - Don't allow removing a window from maximized or fullscreened state - to place the titlebar under the top panel. Fixes #322075. - - * src/display.c (handle_net_moveresize_window): fix up previous - comments now that I know a little more, modify the code just - slightly to clarify that this is NOT a manual user move/resize - operation - - * src/window.c (meta_window_unmaximize, - meta_window_unmake_fullscreen, - meta_window_shove_titlebar_onscreen): - don't claim that these are manual user move/resize operations - -2005-11-21 Elijah Newren <newren@gmail.com> - - * src/constraints.c (constrain_partially_onscreen): Relax the - partially onscreen constraint to allow the titlebar to touch the - bottom panel in order to make the new constraints code function - the same as the old version. Fixes #322071. - -2005-11-21 Elijah Newren <newren@gmail.com> - - * src/constraints.c (place_window_if_needed): When updating the - xinerama due to placement, update which maximal/spanning rect set - to use as well. Fixes #322068. - -2005-11-21 Elijah Newren <newren@gmail.com> - - * doc/strut-and-related-updating.txt: It took me a little while to - figure out how struts & workareas are updated and to learn what - all the related functions were used for so I thought I'd clean up - my notes and make them available. This will probably be more - useful now since regions and edges are also computed and stored at - the same time as the workareas. - -2005-11-20 Elijah Newren <newren@gmail.com> - - * src/constraints.c (place_window_if_needed): compute the frame - geometry due to maximization only after actually maximizing. - Fixes #321902. - -2005-11-21 Davyd Madeley <davyd@fugro-fsi.com.au> - - * src/edge-resistance.c (meta_display_compute_resistance_and_snap): - Use GPOINTER_TO_INT() macro instead of cast to allow compilation on - 64-bit architectures without warning. - -2005-11-19 Elijah Newren <newren@gmail.com> - - * src/edge-resistance.c (apply_edge_resistance): differentiate - between movement towards an edge and movement away from one. Pick - smaller constants for movement away from an edge. - -2005-11-19 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.13.3 - -2005-11-19 Elijah Newren <newren@gmail.com> - - * NEWS: 2.13.2 release - -2005-11-18 Elijah Newren <newren@gmail.com> - - Merge of all the changes on the constraints_experiments branch. - This is just a summary, to get the full ChangeLog of those - changes (approx. 2000 lines): - cvs -q -z3 update -Pd -r constraints_experiments - cvs -q -z3 diff -pu -r CONSTRAINTS_EXPERIMENTS_BRANCHPOINT ChangeLog - - Bugs fixed: - unfiled - constraints.c is overly complicated[1] - unfiled - constraints.c is not robust when all constraints - cannot simultaneously be met (constraints need to be - prioritized) - unfiled - keep-titlebar-onscreen constraint is decoration - unaware (since get_outermost_onscreen_positions() - forgets to include decorations) - unfiled - keyboard snap-moving and snap-resizing snap to hidden - edges - 86644 - resize should have a shift option like move does - 109553 - gravity w/ simultaneous move & resize doesn't work - 113601 - maximize vertical and horizontal should toggle and be - constrained - 122196 - windows show up under vertical panels - 122670 - jerky/random resizing of window via keyboard[2] - 124582 - keyboard and mouse snap-resizing and snap-moving - erroneously moves the window multidimensionally - 136307 - don't allow apps to resize themselves off the screen - (*cough* filechooser *cough*) - 142016, 143784 - windows should not span multiple xineramas - unless placed there by the user - 143145 - clamp new windows to screensize and force them - onscreen, if they'll fit - 144126 - Handle pathological strut lists sanely[3] - 149867 - fixed aspect ratio windows are difficult to resize[4] - 152898 - make screen edges consistent; allow easy slamming of - windows into the left, right, and bottom edges of the - screen too. - 154706 - bouncing weirdness at screen edge with keyboard moving - or resizing - 156699 - avoid struts when placing windows, if possible (nasty - a11y blocker) - 302456 - dragging offscreen too restrictive - 304857 - wireframe moving off the top of the screen is misleading - 308521 - make uni-directional resizing easier with - alt-middle-drag and prevent the occasional super - annoying resize-the-wrong-side(s) behavior - 312007 - snap-resize moves windows with a minimum size - constraint - 312104 - resizing the top of a window can cause the bottom to - grow - 319351 - don't instantly snap on mouse-move-snapping, remove - braindeadedness of having order of releasing shift and - releasing button press matter so much - - [1] fixed in my opinion, anyway. - [2] Actually, it's not totally fixed--it's just annoying - instead of almost completely unusable. Matthias had a - suggestion that may fix the remainder of the problems (see - http://tinyurl.com/bwzuu). - [3] This bug was originally about not-quite-so-pathological - cases but was left open for the worse cases. The code from - the branch handles the remainder of the cases mentioned in - this bug. - [4] Actually, although it's far better there's still some minor - issues left: a slight drift that's only noticeable after - lots of resizing, and potential problems with partially - onscreen constraints due to not clearing any - fixed_directions flags (aspect ratio windows get resized in - both directions and thus aren't fixed in one of them) - - New feature: - 81704 - edge resistance for user move and resize operations; - in particular 3 different kinds of resistance are - implemented: - Pixel-Distance: window movement is resisted when it - aligns with an edge unless the movement is greater than - a threshold number of pixels - Timeout: window movement past an edge is prevented until - a certain amount of time has elapsed during the - operation since the first request to move it past that - edge - Keyboard-Buildup: when moving or resizing with the - keyboard, once a window is aligned with a certain edge - it cannot move past until the correct direction has - been pressed enough times (e.g. 2 or 3 times) - - Major changes: - - constraints.c has been rewritten; very few lines of code from - the old version remain. There is a comment near the top of - the function explaining the basics of how the new framework - works. A more detailed explanation can be found in - doc/how-constraints-works.txt - - edge-resistance.[ch] are new files implementing edge-resistance. - - boxes.[ch] are new files containing low-level error-prone - functions used heavily in constraints.c and edge-resistance.c, - among various places throughout the code. testboxes.c - contains a thorough testsuite for the boxes.[ch] functions - compiled into a program, testboxes. - - meta_window_move_resize_internal() *must* be told the gravity - of the associated operation (if it's just a move operation, - the gravity will be ignored, but for resize and move+resize - the correct value is needed) - - the craziness of different values that - meta_window_move_resize_internal() accepts has been documented - in a large comment at the beginning of the function. It may - be possible to clean this up some, but until then things will - remain as they were before--caller beware. - - screen and xinerama usable areas (i.e. places not covered by - e.g. panels) are cached in the workspace now, as are the - screen and xinerama edges. These get updated with the - workarea in src/workspace.c:ensure_work_areas_validated() - -2005-11-14 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.13.2 - -2005-11-14 Elijah Newren <newren@gmail.com> - - * NEWS: 2.13.1 release - -2005-11-11 Aidan Delaney <a.j.delaney@brighton.ac.uk> - - * src/tabpopup.h: (struct _MetaTabEntry): - * src/tabpopup.c: (meta_ui_tab_popup_new): - * src/screen.c: (meta_screen_ensure_tab_popup): - Changed the 'minimized' field of the MetaTabEntry struct to - 'hidden'. Fixes reopened bug #168455. - -2005-10-29 Kjartan Maraas <kmaraas@gnome.org> - - * src/eventqueue.c: (meta_event_queue_new): Merge fix - for bug #320050 from stable. - -2005-10-27 Erdal Ronahi <erdal.ronahi@gmail.com> - - * configure.in: Added ku (Kurdish) to ALL_LINGUAS - -2005-10-25 Philip O'Brien <philip.obrien@dal.ca> - - * src/prefs.c (meta_preference_to_string): add handling for - META_PREF_CURSOR_THEME and META_PREF_CURSOR_SIZE for more complete - debug info - -2005-10-24 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.13.1 - -2005-10-24 Elijah Newren <newren@gmail.com> - - * NEWS: 2.13.0 release - -2005-10-23 Elijah Newren <newren@gmail.com> - - Fix edge snapping for multi-screen (non-xinerama) setups. #319425 - - * src/place.c (get_windows_showing_on_same_screen, - get_vertical_edges, get_horizontal_edges): rename - get_windows_on_same_workspace() to - get_windows_showing_on_same_screen() - - * src/place.c (get_windows_showing_on_same_screen): exclude windows - in the list that are on a different screen - -2005-10-20 Elijah Newren <newren@gmail.com> - - * HACKING: Clarify why METACITY_VERBOSE=1 is bad without - META_USE_LOGFILE=1; point to bug 305091 for details. - -2005-10-13 Muktha <muktha.narayan@wipro.com> - - * src/themes/Simple/metacity-theme-1.xml: Make the unfocussed - Simple window border visible with high contrast inverse theme. - Fixes #121361. - -2005-10-08 Elijah Newren <newren@gmail.com> - - Fix a crash that occurs when removing some virtual desktops and - windows happen to be on those desktops. #318306. - - * src/workspace.c (meta_workspace_relocate_windows): Since windows - cannot be on more than one workspace at a time, remove the window - from the old workspace before adding it to the new one. - -2005-10-08 Elijah Newren <newren@gmail.com> - - Add my copyright notice to a number of files on which it should - already exist. - -2005-10-03 Elijah Newren <newren@gmail.com> - - * src/metacity.schemas.in: clarify the meaning of the auto_raise - preference. Fixes one of the issues in #312421. - -2005-10-03 Elijah Newren <newren@gmail.com> - - Patch from Ross Cohen to make alt-esc consistent with alt-tab by - leaving stacking of unselected windows unchanged. Fixes #314285. - - * src/keybindings.c (process_tab_grab): before raising and showing - the next candidate, reset the stack positions to what they were - at the beginning of the grab - -2005-10-03 Elijah Newren <newren@gmail.com> - - Patch from Ross Cohen to make alt-esc (show windows instantly) - actually show minimized windows too. Fixes #107072. - - * src/keybindings.c (process_tab_grab): initialize tab_unminimized - to FALSE for the target window when starting the grab, when - advancing through the list check to find the previous window and - re-minimize it if it was tab-unminimized, unminimize the new - window we're alt-esc'ing to if it's minimized, (do_choose_window): - raise and unminimize the initial window as well in alt-esc'ing - - * src/window.h (struct _MetaWindow): add a tab_unminimized field - - * src/window.c (meta_window_new_with_attrs): initialize - tab_unminimized to false - -2005-10-03 Elijah Newren <newren@gmail.com> - - Branched for Gnome 2.13. :-) - - * configure.in: bump version to 2.13.0. Add UNSTABLE warning. - * README: add 2.13.x to the list of unstable branches - -2005-10-03 Elijah Newren <newren@gmail.com> - - A combination of a couple memory leaks fixes, from Kjartan, - Soeren, and I. Fixes #313030. - - * src/bell.c (meta_bell_flash_screen): call XFreeGC() - - * src/frames.c (invalidate_cache): free pixels - - * src/window.c (meta_window_show_menu): call - meta_screen_free_workspace_layout() - -2005-10-03 Elijah Newren <newren@gmail.com> - - Patch from Björn Lindqvist fix the workspace switcher tabpopup to - display the right windows and to fix the - pick-a-new-window-to-focus algorithm in order to not select - windows that aren't showing. Fixes #170475. - - * src/tabpopup.c (meta_convert_meta_to_wnck, - meta_select_workspace_expose_event): factor out conversion code - from meta_select_workspace_expose_event() into the new - meta_convert_meta_to_wnck() function - - * src/tabpopup.c (meta_select_workspace_expose_event): - * src/workspace.c (focus_ancestor_or_mru_window): - replace the buggy window->minimized logic with - !meta_window_showing_on_its_workspace (window) - -2005-10-03 Elijah Newren <newren@gmail.com> - - Patch from Björn Lindqvist to have ancestors come along with the - transient when moving the window from one workspace to another. - Fixes #314977. - - * src/window.c (meta_window_change_workspace): have all ancestors - change workspaces too - -2005-10-03 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.12.2 - -2005-10-03 Elijah Newren <newren@gmail.com> - - * NEWS: 2.12.1 release - -2005-10-03 Elijah Newren <newren@gmail.com> - - Truncate ridiculously long titles to avoid crashing or letting the - pager crash. Based on patch from Ray, incorporating suggestions - from Havoc and some extensions of my own. Fixes #315070. - - * src/display.c (set_utf8_string_hint, meta_display_open): - * src/xprops.[ch] (meta_prop_set_utf8_string_hint): - Move set_utf8_string_hint() to props.[ch], namespace it - ("meta_prop_"), and make it public - - * src/tabpopup.c (utf8_strndup, meta_ui_tab_popup_new): - * src/util.[ch] (meta_g_utf8_strndup): - Move utf8_strndup() to util.[ch], namespace it ("meta_g_"), and - make it public - - * src/display.c (meta_display_open): - * src/display.h (struct _MetaDisplay): - add net_wm_visible_name and net_wm_visible_icon_name atoms to the - list of atoms we work with - - * src/window-props.c (set_window_title, set_icon_title): If title - length is greater than 512, truncate it and set - _NET_WM_VISIBLE_NAME or _NET_WM_VISIBLE_ICON_NAME accordingly - -2005-10-03 Elijah Newren <newren@gmail.com> - - Get the tabbing window outline to work with gtk+ 2.8.4 again. - Fixes #317528. - - * src/tabpopup.c (display_entry): gtk+ 2.8.4 needs to know the - mapped state of its windows (see bug 316180), and since we - manually map with gdk_window_show_unraised() we need to manually - set the mapped state too - -2005-09-05 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.12.1 - -2005-09-05 Elijah Newren <newren@gmail.com> - - * configure.in: - * README: - * NEWS: - 2.12.0 release - -2005-09-04 Danilo Šegan <danilo@gnome.org> - - * configure.in: Added Armenian (hy) to ALL_LINGUAS. - -2005-09-03 Elijah Newren <newren@gmail.com> - - * HACKING: Add tips on how to more easily get the ids of windows, - and how to shorten xprop output. - -2005-09-02 Brent Smith <gnome@nextreality.net> - - * src/place.c: (meta_window_place): Moved the call to - meta_screen_get_natural_xinerama_list to earlier in - function so that xineramas_list is allocated before - find_first_fit is called. Fixes #315000 - -2005-08-22 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.11.5 - -2005-08-22 Elijah Newren <newren@gmail.com> - - * NEWS: 2.11.3 release - -2005-08-22 Elijah Newren <newren@gmail.com> - - * configure.in: Patch from Björn Lindqvist to check for the - appropriate versions of glib and gtk. Fixes #314116. - -2005-08-12 Elijah Newren <newren@gmail.com> - - * src/place.c (meta_window_place): Avoid obscuring - centered-on-desktop windows which are denied focus. Fixes - #313234. - -2005-08-08 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.11.3 - -2005-08-08 Elijah Newren <newren@gmail.com> - - * NEWS: 2.11.2 release - -2005-08-08 Elijah Newren <newren@gmail.com> - - Patch from Brent Smith to fix a duplicate string. Fixes #309774. - - * src/theme-parser.c (parse_toplevel_element, parse_draw_op_element): - Change "No \"%s\" attribute on element <%s>" string to "No \"%s\" - attribute on <%s> element" - -2005-08-03 Ray Strode <rstrode@redhat.com> - - Improve the behavior of keyboard move/resize and edge - snapping. Still not perfect, bug 310888. - - * src/effects.c (draw_xor_rect): Make the outside of a - wireframe rectangle line up with the outside edge of its - window, instead of centering the wireframe edges on the - window edges. - - * src/keybindings.c (process_keyboard_move_grab): allow - edge snapping in wireframe mode. Adjust code to take - into account changed semantics of find_next_*_edge - functions. - (process_keyboard_resize_grab_op_change): new function - to take some orthogonal logic out of - process_keyboard_resize_grab_op. Only allow keyboard - resize cursor to go to flat edges, not corners. - (process_keyboard_resize_grab): allow edge snapping in - wireframe mode. Fix up snapping logic. - - * src/place.c (get_{vertical,horizontal}_edges): use - GArray instead of int *, since the number of output - edges isn't known until the middle of the function now. - Use xor rect extents instead of window extends if in - wireframe mode. - (meta_window_find_next_{vertical,horizontal}_edge: add - new source_edge_position parameter to specify which edge - on the active window to start from when looking for next - edge on the screen. Return the coordinate of the edge - found and not the coordinate of where the window should be - moved to snap to where the edge was found. - - * src/window.c (update_move): all the user to specify - an edge to resize with mouse in keyboard resize mode. - window - -2005-08-01 Elijah Newren <newren@gmail.com> - - * src/metacity.schemas.in: Change default theme from "Simple" to - "Clearlooks". - -2005-07-31 Elijah Newren <newren@gmail.com> - - * src/stack.c (is_focused_foreach, get_standalone_layer): use only - the expected_focus_window instead of both the focused_window and - the expected_focus_window. Removes an infinite flicker loop in - sloppy and mouse focus, and an ugly one time flicker in click to - focus. Fixes #311400. - -2005-07-30 Elijah Newren <newren@gmail.com> - - Patch from Jaap Haitsma to make sure that Metacity dialogs have - icons. Fixes #309876. - - * src/metacity-dialog.c (kill_window_question, - warn_about_no_sm_support, error_about_command): call - gtk_window_set_icon_name() to set the dialog icon - -2005-07-28 Elijah Newren <newren@gmail.com> - - * src/place.c (avoid_being_obscured_as_second_modal_dialog): - remove some unneeded debug spew that was causing crashes. Fixes - #311819. - -2005-07-24 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.11.2 - -2005-07-24 Elijah Newren <newren@gmail.com> - - * NEWS: 2.11.1 release - -2005-07-24 Elijah Newren <newren@gmail.com> - - * src/place.c (find_most_freespace): try to place windows denied - focus near the focus window and fix a xinerama bug with the - placement, (avoid_being_obscured_as_a_second_modal_dialog): avoid - modal dialogs being obscured in somewhat pathologically strange - circumstances that Eclipse seems to be good at triggering, - (meta_window_place): have dialog windows make use of - avoid_being_obscured_as_a_second_modal_dialog(). Fixes one of the - issues found in #307875. - -2005-07-24 Elijah Newren <newren@gmail.com> - - * src/window.c (meta_window_raise): raise the window as well as - its ancestor; fixes a stacking bug with an ancestor that has more - than one child window. Fixes one of the issues in #307875. - -2005-07-24 Elijah Newren <newren@gmail.com> - - * src/window.c (meta_window_free): restore original window size if - the window was maximized, as the FIXME says. ;-) Fixes #137185. - Thanks to Christian Persch for the testcase that made this easier - to track down. - -2005-07-23 Elijah Newren <newren@gmail.com> - - * src/window.c (meta_window_activate): revert the patch from - #128380--change _NET_ACTIVE_WINDOW behavior to what it originally - was. - -2005-07-18 Matthias Clasen <mclasen@redhat.com> - - * configure.in: Add checks for Xcursor, to make the changes - done on 2005-07-11 effective. - -2005-07-14 Elijah Newren <newren@gmail.com> - - Patch from Ken Harris to provide a more lenient threshold for - drawing rounded corners. Fixes #122065. - - * src/theme.c (meta_frame_layout_calc_geometry): use height + - width > 5 instead of height > 3 && width > 3 as criterion - -2005-07-13 Elijah Newren <newren@gmail.com> - - Fix a slight bug (causing possible miscoloring of parts of the - titlebar) introduced by the patch from #169982. - - * src/gradient.c: - (meta_gradient_create_interwoven): - (meta_gradient_create_multi_vertical): - - bitshifting operators do not take precedence over typecasting, so - make sure to use parentheses to get the right operation order. - -2005-07-12 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.11.1 - -2005-07-12 Elijah Newren <newren@gmail.com> - - * NEWS: 2.11.0 release - -2005-07-12 Elijah Newren <newren@gmail.com> - - Patch from Andrew Johnson to speed up vertical gradients. Fixes - #169982. - - * src/gradient.c: - (meta_gradient_create_interwoven): - (meta_gradient_create_vertical): - (meta_gradient_create_multi_vertical): - - use memcpy instead of really long loops to set values in memory to - a given pattern. - -2005-07-12 Elijah Newren <newren@gmail.com> - - Patch from Björn Lindqvist to split up main() into more manageable - chunks and make use of GOpt. Closes #305331. - - * src/main.c (usage): remove this function, - (meta_print_compilation_info): new function taken from main(), - (meta_print_self_identity): new function taken from main(), - (struct MetaArguments) new struct to replace some free variables, - (meta_parse_options): new funcion taken from main() but now using - GOpt, (meta_select_display): new function taken from main() - -2005-07-12 Aivars Kalvans <aivars.kalvans@inbox.lv> - - * src/screen.c (meta_screen_free): free ->xinerama_infos - Closes #307884 - -2005-07-11 Elijah Newren <newren@gmail.com> - - Stuff I forgot to do when I branched an hour or so ago before - Matthias' commit... - - * configure.in: bump version to 2.11.0. Add UNSTABLE warning. - * README: add 2.11.x to the list of unstable branches - -2005-07-11 Matthias Clasen <mclasen@redhat.com> - - React to cursor theme changes: (#308106) - - * src/prefs.h: - * src/prefs.c: Expose the GConf keys for cursor theme - and size as preferences META_PREF_CURSOR_THEME and - META_PREF_CURSOR_SIZE with getters meta_prefs_get_cursor_theme() - and meta_prefs_get_cursor_size(). - - * src/display.c (meta_display_open): Initialize the cursor - theme and size. - - * src/display.h: - * src/display.c (meta_display_set_cursor_theme): New function - to change the cursor theme and update all cursors. - - * src/screen.h - * src/screen.c (meta_screen_update_cursor): New function to - refesh the root cursor of a screen. - - * src/main.c (prefs_changed_callback): Update the cursor - theme when the cursor preferences change. - -2005-06-27 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.10.3 - -2005-06-27 Elijah Newren <newren@gmail.com> - - * NEWS: 2.10.2 release - -Sun Jun 26 11:19:18 2005 Soeren Sandmann <sandmann@redhat.com> - - * src/frames.c: Add a cache of pixmaps for recently exposed frame - areas. Makes metacity a bit faster when dragging windows around. - See bug 141813. - -2005-06-10 Ryan Lortie <desrt@desrt.ca> - - * src/frames.c: Prevent using the address of a local variable - as a hash key. (Bug #307209) - - * src/xprops.c (meta_prop_get_values): Fix a small leak in the - case of a SYNC_COUNTER property value and HAVE_XSYNC not - defined. (Bug #307214) - -2005-06-07 Ray Strode <rstrode@redhat.com> - - Cleanup font data when done with it (bug 306720). - - * src/effects.c (draw_xor_rect): free font info structure. - * src/screen.c (meta_screen_new): pass a 1 not a 0 to - XFreeFontInfo to free font info structure. - (meta_screen_free): call XUnloadFont on GC font before freeing - the GC. - -2005-06-02 Elijah Newren <newren@gmail.com> - - * src/window.c (meta_window_focus): if the window has a modal - transient which is being unmanaged, don't focus it. Fixes the - Metacity issue reported in #305362. - -2005-05-30 Ray Strode <rstrode@redhat.com> - - Bug 305564 again. - - When drawing XOR resize popup use "fixed" font instead of - -misc-fixed-*-16-* xlfd. Should work on more xservers. - - Also take steps to fail better if the xserver isn't - cooperating. - - * src/effects.c (draw_xor_rect): if we can't draw font box - for whatever reason, at least draw grid frames. - - * src/screen.c (meta_screen_new): use fixed alias instead - of a xfld. Don't pass GCFont to XCreateGC if font couldn't - be loaded. Print a warning if font couldn't be loaded. - -2005-05-26 Elijah Newren <newren@gmail.com> - - * HACKING: Add a clarification that METACITY_VERBOSE needs to be - accompanied by METACITY_USE_LOGFILE - -2005-05-26 Elijah Newren <newren@gmail.com> - - * src/window.c (meta_window_configure_request): Patch from Greg - Hudson to make sure window position is calculated correctly for - reconfigure requests when part of the XWindowChanges structure is - uninitialized. Fixes #305257. - -2005-05-26 Ray Strode <rstrode@redhat.com> - - Actually commit the stuff mentioned in the last - ChangeLog entry. - -2005-05-26 Ray Strode <rstrode@redhat.com> - - Add a resize popup when resizing constrained - windows, (bug 305564). - - * src/display.c: - (meta_display_begin_grab_op), - (meta_display_end_grab_op): - * src/keybindings.c (process_keyboard_move_grab), - (process_keyboard_resize_grab): Call - meta_window_{begin,update,end}_wireframe convenience - functions instead of the meta_effects counterparts. - - * src/display.h: keep track of old wireframe geometry to - clean up xor popup on resize - - * src/effects.[ch] (meta_effects_begin_wireframe), - (meta_effects_update_wireframe), - (meta_effects_end_wireframe), - (draw_xor_rect): take optional width and height arguments - to show to user in resize popup. Draw resize popup if - width and height >= 0 and wireframe isn't smaller than - the popup would be. - - * src/screen.c (meta_screen_new): load a largish font for - the resize popup - - * src/window.[ch] - (meta_window_move_resize_internal): update - wireframe resize popup when the window is resized. - (meta_window_get_wireframe_geometry): new function to - calculate the numbers to display in resize popup - (meta_window_begin_wireframe), - (meta_window_update_wireframe), - (meta_window_end_wireframe): new functions to reduce - repetitive wireframe code. Functions handle updating - wireframe and resize popup geometry. - (update_move), (update_resize), - (meta_window_refresh_resize_popup): remove fixme and - add debug message. - -2005-05-26 Elijah Newren <newren@gmail.com> - - * src/window.c (check_maximize_to_work_area): don't accidentally - treat maximize vertically as maximize in both directions. Fixes - #302204. - -2005-05-26 Elijah Newren <newren@gmail.com> - - * src/window.c (meta_window_new_with_attrs): put all transients - of the new window, if any exist, in the calc_showing queue. Fixes - #303284. Thanks to Billy Biggs for the testcase that made this - easy to track down. - -2005-04-11 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.10.2 - -2005-04-11 Elijah Newren <newren@gmail.com> - - * NEWS: 2.10.1 release - -2005-04-05 Dan Winship <danw@novell.com> - - * src/metacity-dialog.c (warn_about_no_sm_support): Make sure the - "Close" button has the focus, not the table. (#172703) - -2005-04-05 Pawan Chitrakar <pawan@nplinux.org> - - * configure.in: Added ne in ALL_LINGUAS - -2005-03-31 Steve Murphy <murf@e-tools.com> - - * configure.in: Added "rw" to ALL_LINGUAS. - -2005-03-17 Lex Hider <Lex.Hider@gmail.com> - - * doc/Makefile.am (EXTRA_DIST): add doc/code-overview.txt and - doc/how-to-get-focus-right.txt - -2005-03-10 Adi Attar <aattar@cvs.gnome.org> - - * configure.in: Added "xh" to ALL_LINGUAS. - -2005-03-07 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.10.1 - -2005-03-07 Elijah Newren <newren@gmail.com> - - * configure.in: - * README: - * NEWS: - 2.10.0 release - -2005-02-28 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.9.55 - -2005-02-28 Elijah Newren <newren@gmail.com> - - * NEWS: Metacity 2.9.34 unstable release - -2005-02-28 Elijah Newren <newren@gmail.com> - - Patch from Aidan Delaney to make sure that icons in the alt-tab - popup are dimmed for all hidden windows, not just minimized ones. - Fixes #168455. - - * src/screen.c: (meta_screen_ensure_tab_popup): make use - meta_window_showing_on_its_workspace() instead of just checking if - the window is minimized. - -2005-02-25 Elijah Newren <newren@gmail.com> - - Prevent the visual bell from changing the focus window. Fixes - #123366. - - * src/bell.c: (meta_bell_flash_screen): if not in click-to-focus - mode and mouse_mode is also false, increment the focus sentinel so - that we can ignore spurious EnterNotify and LeaveNotify events. - - * src.display.c: (event_callback): make sure to also ignore - LeaveNotify events when the focus sentinel isn't clear - -2005-02-23 Elijah Newren <newren@gmail.com> - - * src/window.c: (meta_window_new_with_attrs): Fix crash that - occurs when stupid apps claim that a window is its own parent. - #168207 - -2005-02-21 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.9.34 - -2005-02-21 Elijah Newren <newren@gmail.com> - - * NEWS: Metacity 2.9.21 unstable release - -2005-02-21 Elijah Newren <newren@gmail.com> - - Handle keynav vs. mousenav in mouse and sloppy focus modes. Fixes - #167545. - - * doc/how-to-get-focus-right.txt: Update due to this new method - for handling keynav vs. mousenav, plus various other updates that - I previously forgot. - - * src/display.h: (struct _MetaDisplay): add a mouse_mode boolean - - * src/display.c: (meta_display_open): initialize mouse_mode to - true, (event_callback): have EnterNotify and LeaveNotify events - set mouse_mode to true when focusing a window - - * src/keybindings.c: (process_tab_grab): set mouse_mode to false - when using alt-tab/alt-esc, (do_choose_window): likewise, - (do_handle_move_to_workspace): set mouse_mode to false on - move-window-to-workspace-<n> keybindings - - * src/window.c (idle_calc_showing): if we're in keynav mode while - using sloppy or mouse focus, use metacity_sentinel to avoid - EnterNotify events being generated from events other than mouse - movement. - - * src/workspace.c (meta_workspace_activate_with_focus): add a - FIXME in a potentially duplicate section of code, - (meta_workspace_focus_default_window): use the same focus choice - as click-to-focus if in keynav mode. - -2005-02-20 Elijah Newren <newren@gmail.com> - - * src/display.c: (event_callback): Handle _NET_CURRENT_DESKTOP - messages that come with timestamps. Fixes the metacity portion of - #161361 other than the portion handled by #128380. - -2005-02-20 Elijah Newren <newren@gmail.com> - - * src/window.c: (meta_window_activate): when receiving a - _NET_ACTIVE_WINDOW message, switch to the desktop where the window - is located before activating instead of moving the window to the - current desktop. Thanks to Lubos Lunak for catching this issue. - Fixes #128380. - -2005-02-20 Elijah Newren <newren@gmail.com> - - * src/window.c (meta_window_show): Ignore all focus and - focus-stealing-prevention code in meta_window_show when not - showing the window for the first time. Fixes #167199. - -2005-02-20 Elijah Newren <newren@gmail.com> - - Fix an obscure xinerama placement bug with windows that are too - large to fit in the workarea in both dimensions. #166757 - - * src/place.c: (meta_window_place): use the current xinerama - instead of arbitrarily resetting to 0 - -2005-02-20 Elijah Newren <newren@gmail.com> - - Patch from Joe Marcus Clarke to fix a possible crash on logout. - #167935. Thanks for fixing my mistakes, Joe! - - * src/display.c: (meta_display_open): initialize - display->grab_old_window_stacking to NULL. - -2005-02-20 Elijah Newren <newren@gmail.com> - - Big patch to cover about 6 different issues in order to correct - rare problems with timestamps (make sure window selected in - tasklist actually gets focus, sanity check timestamps to avoid - rogue apps hosing the system, correct the updating of - net_wm_user_time, correctly handle timestamps of 0 when comparing - xserver timestamps for those who have had their systems up for - over 25 days or so, add some debugging information to verbose - logs, some code cleanups). Fixes all issues listed in #167358. - - * src/display.h: (struct _MetaDisplay): clarify comment on - last_focus_time, introduce a new variable--last_user_time, - (XSERVER_TIME_IS_BEFORE macro): put this functionality into a - separate macro and then introduce a new macro with this name that - uses the old one but adds additional special-case checks for - timestamps that are 0, (comment to - meta_display_set_input_focus_window): add information about how - last_user_time should be used in this function - - * src/display.c (santiy_check_timestamps): new function, - (meta_display_open): intialize display->last_user_time, - (meta_display_get_current_time_roundtrip): use the timestamp, - which is known to be good, in order to sanity_check_timestamps, - (event_callback): use the new meta_window_ste_user_time() function - in order to correct problems, use the timestamp of KeyPress and - ButtonPress events, which are known to be good, in order to - sanity_check_timestamps, (timestamp_too_old): new function for - common behavior of meta_display_focus_the_no_focus_window and - meta_display_set_input_focus_window, with added checking for - display->last_user_time in addition to display->last_focus_time, - (meta_display_set_input_focus_window): replace some of the code - with a call to timestamp_too_old(), - (meta_display_focus_the_no_focus_window): replace some of th ecode - with a call to timestamp_too_old() - - * src/window.h: (meta_window_set_user_time): new function to - abstract the many things that need to be done when updating the - net_wm_user_time of any window - - * src/window.c: (meta_window_activate): add debugging spew, make - sure the comparison is made with last_user_time NOT - last_focus_time, use meta_window_set_user_time() function in order - to correct problems, (meta_window_client_message): add a newline - to a debugging message to make them easier to read, - (meta_window_set_user_time): new function - - * src/window-props.c (reload_net_wm_user_time): use the new - meta_window_ste_user_time() function in order to correct problems - -2005-02-16 Elijah Newren <newren@gmail.com> - - * src/display.c: (event_callback): trivial fix to a log message: - change %d to %lu (see debugging log from bug 167358). - -2005-02-12 Elijah Newren <newren@gmail.com> - - Raise the ancestor of a window instead of the window itself. - Fixes #166894. - - * src/window.c: (find_root_ancestor): new function, - (meta_window_raise): get the ancestor of the given window and - raise it if possible instead of the window - -2005-02-12 Elijah Newren <newren@gmail.com> - - Don't unconditionally place splashscreens (and other - not-to-be-focused windows) below the focus window. Fixes #167042. - - * src/window.c: (intervening_user_event_occurred): new function - taken from the timestamp comparison portion of the old - window_takes_focus_on_map function, (window_state_on_map): new - function with remainder of old window_takes_focus_on_map function - that determines both whether the window will take focus and - whether it should be placed on top, (meta_window_show): use - place_on_top_on_map to determine window stacking instead of trying - to infer it from takes_focus_on_map - -2005-02-11 Elijah Newren <newren@gmail.com> - - Avoid new windows being obscured by the focus window (and thus - possibly lost). Fixes #166524. - - * src/place.c: new MetaWindowDirection enum, - (find_most_freespace): new function to find where there is the - most space available around the focused window, - (meta_window_place): if a window is denied focus and the window - overlaps the focused window, retry the first-fit algorithm only - paying attention to the focus window position and if that fails - just find the location on the screen with the most space - available. - - * src/window.h: (struct MetaWindow): new - denied_focus_and_not_transient bitfield - - * src/window.c: (meta_window_new_with_attrs): initialize - denied_focus_and_not_transient, (meta_window_show): set and unset - the denied_focus_and_not_transient field appropriately - -2005-02-08 Aidan Delaney <adelaney@cs.may.ie> - - Removed useless function call. #166730 - - * src/tabpopup.c: (outline_window_expose): Removed unused - references to variables and an unnecessary function call to - gdk_window_get_size(). - -2005-02-08 Elijah Newren <newren@gmail.com> - - Avoid using CurrentTime when focusing, handle it better in case we - miss any cases. Fixes #166732. - - * src/window.c: (meta_window_shade): use - meta_display_get_current_time_roundtrip() to ensure we have a - valid timestamp, (meta_window_unshade): same - - * src/display.c: (meta_display_set_input_focus_window): If - CurrentTime was passed, get one from the XServer in addition to - throwing a warning, (meta_display_focus_the_no_focus_window): same - -2005-02-08 Elijah Newren <newren@gmail.com> - - * src/window.c: (meta_window_activate): If we're not passed a - timestamp, make sure to manually get one. Fixes #166728. - -2005-02-07 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.9.21 - -2005-02-07 Elijah Newren <newren@gmail.com> - - * NEWS: Metacity 2.9.13 unstable release - -2005-02-06 Elijah Newren <newren@gmail.com> - - Set a _METACITY_VERSION property (a utf8 string) on the WM check - window. #165350. - - * src/display.h: (struct MetaDisplay): add a atom_metacity_version - field - - * src/display.c: (meta_display_open): initialize the - _METACITY_VERSION property on the WM check window to the current - version of Metacity. - -2005-02-06 Elijah Newren <newren@gmail.com> - - Ignore xconfigurerequest events for stacking when it should be - safe to do so. Again, thanks to Crispin Flowerday for the test - case. Thanks to KWin for the inspiration (and to Google for - indexing their source code). Fixes the other half of #166395. - - * src/window.c: (meta_window_configure_request): if the - active_window is from a separate application than the one getting - the configure request and the net_wm_user_time of the active - window is later than that of the window getting the configure - request, then ignore the request. - -2005-02-06 Elijah Newren <newren@gmail.com> - - If activation requests are too old, set the demands_attention hint - instead of actually activating. Thanks to Crispin Flowerday for - the test case and for testing the patch. Fixes half of #166395. - - * src/window.c: (meta_window_activate): if the request came before - the last focus time, set the demands attention hint instead - -2005-02-04 Dave Ahlswede <mightyquinn@letterboxes.org> - - * src/metacity.schemas.in: Add period to the end of - reduced_resources' description. Fixes #165780. - -2005-02-04 Elijah Newren <newren@gmail.com> - - Make sure window->border_only is initialized so we don't get - random windows without decorations. Thanks to Sinisa Segvic and - Owen Taylor for providing test cases. Fixes #145131. - - * src/window.c: (update_mwm_hints): Be sure to call - recalc_window_features even if no MWM hints are set - -2005-02-02 Elijah Newren <newren@gmail.com> - - Focus parents of dismissed transient windows in preference to the - window that most recently had keyboard focus. Fixes #157360. - - * doc/how-to-get-focus-right.txt: Note the distinction between - "most recently used window" and "most recent to have keyboard - focus" that we are now making. - - * src/workspace.c: (focus_ancestor_or_mru_window): rename from - meta_workspace_focus_mru_window, and first check whether we need - to focus an ancestor window before looking for the mru window, - (record_ancestor): helper function for - focus_ancestor_or_mru_window, - (meta_workspace_focus_default_window): update due to the function - rename from meta_workspace_focus_mru_window to - focus_ancestor_or_mru_window - -2005-01-31 Elijah Newren <newren@gmail.com> - - Try 2 to correct misleading and inaccurate wording. Hopefully, - really fixes #165380. - - * src/menu.c: Change wording of menu from "Always on Current - Workspace" to "Always on Visible Workspace". "Always on Current - Workspace" could sound like a synonym of "Only on This Workspace" - when it was supposed to be the opposite. - -2005-01-31 Elijah Newren <newren@gmail.com> - - Correct the stacking when return from fullscreen mode. Fixes - #165718. - - * src/window.c: (meta_window_unmake_fullscreen): Update the layer - after resizing the window - -2005-01-31 Muktha <muktha.narayan@wipro.com> - - src/themes/Atlanta/metacity-theme-1.xml: - src/themes/Simple/metacity-theme-1.xml: - src/themes/Bright/metacity-theme-1.xml: - Make the unfocussed title bar distinguishable. Fixes #125291. - -2005-01-28 Elijah Newren <newren@gmail.com> - - Patch from RHEL-3 (Havoc doesn't remember how it got there) that - Havoc posted in bug 156511 to fix the problem with fullscreen - windows on a different xinerama monitor not staying on top. I - updated to HEAD. Should fix #156511. - - * src/stack.c: (windows_on_different_xinerama): new function, - (get_standalone_layer): let windows on a different screen than the - one with the focus window stay in the fullscreen layer - -2005-01-28 Elijah Newren <newren@gmail.com> - - * src/metacity-dialog.c: (warn_about_no_sm_support): make this - dialog be sticky. Fixes #164745. - -2005-01-28 Elijah Newren <newren@gmail.com> - - Patch from Tim Herold to handle xcomposite pkgconfig version - regression. Fixes #149368. - - * configure.in: Change XCOMPOSITE_VERSION from 1.0 to 0.2 - -2005-01-28 Elijah Newren <newren@gmail.com> - - Correct misleading and inaccurate wording. Fixes #165380. - - * src/menu.c: Change wording of menu to "Always on Current - Workspace" from "Put on All Workspaces", remove a quick-key - conflict between "On _Top" and "Only on _This Workspace" by - switching the latter to "_Only on This Workspace" - - * src/window.c: Remove a comment that is no longer necessary - (since bug 87531 has been fixed) - -2005-01-28 Elijah Newren <newren@gmail.com> - - Take into account the appropriate list of windows when placing a - new one. Fixes #165381. - - * src/place.c: (meta_window_place): use - meta_window_showing_on_its_workspace(w) instead of !w->minimzed, - also take into account sticky windows - - * src/window.[ch]: rename window_showing_on_its_workspace to - meta_window_showing_on_its_workspace and export it - -2005-01-27 Elijah Newren <newren@gmail.com> - - Plug a pair of leaks. Fixes #165378 - - * src/place.c: (meta_window_place, get_windows_on_same_workspace): - free list returned by meta_display_list_windows. - -2005-01-27 Elijah Newren <newren@gmail.com> - - Treat splashscreens same as other windows for stacking. Fixes - #165243. - - * src/stack.h: (MetaStackLayer enum): remove META_LAYER_SPLASH - from the list - - * src/stack.c: (get_standalone_layer): remove the special casing - of META_WINDOW_SPLASHSCREEN - -2005-01-27 Elijah Newren <newren@gmail.com> - - * src/window.c: (set_net_wm_state): shaded windows should not show - up in pagers. Fixes #165377. - -2005-01-26 Elijah Newren <newren@gmail.com> - - Stick and unstick transients with their parent automatically. - Fixes #152283. - - * src/window.c: (window_stick_impl, window_unstick_impl): rename - from meta_window_stick and meta_window_unstick respectively, - (stick_foreach_func): a function to assist calling - window_(un)stick_impl on each transient, (meta_window_stick, - meta_window_unstick): new functions that call window_stick_impl or - window_unstick_impl for the window and each of its transients. - -2005-01-26 Elijah Newren <newren@gmail.com> - - Patch from John Paul Wallington to keep tooltip on screen - horizontally for xinerama. Fixes #165261. - - * src/fixedtip.c: (meta_fixed_tip_show): rename screen_width and - screen_height to screen_right_edge and screen_bottom_edge, set - them using xinerama info instead of just screen geometry, and use - them to determine where to place the tooltip window. - -2005-01-26 Arvind Samptur <arvind.samptur@wipro.com> - - Don't wireframe when accessibility is on, it apparently - causes a desktop wide freeze. - - * src/prefs.[ch] (meta_prefs_init) (change_notify) - (update_gnome_accessibility) (meta_preference_to_string) - (meta_prefs_get_gnome_accessibility) : Add code to monitor - accessibility status. - - * src/display.c (meta_display_begin_grab_op): Check - accessibility status before going ahead with wireframe. - Fixes #159538 - -2005-01-25 Elijah Newren <newren@gmail.com> - - * src/tabpopup.c: (meta_select_workspace_expose_event): ignore - sticky windows for non-active workspaces. Fixes #165259. - -2005-01-25 Elijah Newren <newren@gmail.com> - - * src/window.c: (meta_window_new_with_attrs): set the window state - hints _after_ applying session information. Fixes #164677. - -2005-01-25 Elijah Newren <newren@gmail.com> - - Add man pages for metacity-window-demo and metacity-theme-viewer. - Man pages from Jose Moya, auto-fu from Dave Ahlswede. (#143513) - - * doc/man/metacity-theme-viewer.1: - * doc/man/metacity-window-demo.1: - - New man pages - - * doc/man/Makefile.am: - * doc/Makefile.am: - * configure.in: - - Make sure to install the man pages - - * doc/man/.cvsignore: - - Silence cvs - -2005-01-25 Benjamin Kahn <xkahn@novell.com> - - New 48x48 default icon as specified in bug #160660 - -2005-01-25 Elijah Newren <newren@math.utah.edu> - - Patch from Stephane LOEUILLET in bug #151850. - - * src/metacity.desktop.in: specify encoding - -2005-01-25 Balamurali Viswanathan <balamurali.viswanathan@wipro.com> - - * src/prefs.c (meta_prefs_init): Get gconf to load the - terminal dir so that we get the notifications when - the command is changed. Fixes bug #160934 - -2005-01-25 Elijah Newren <newren@gmail.com> - - Refuse to focus a window with a modal transient, and focus the - transient instead. Fixes #164716. - - * src/window.c: (get_modal_transient): new function, - (meta_window_focus): if the window has a modal transient, make - sure it is on the current workspace and then focus it instead. - -2005-01-24 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.9.13 - -2005-01-24 Elijah Newren <newren@gmail.com> - - * NEWS: Metacity 2.9.8 unstable release - -2005-01-24 Elijah Newren <newren@gmail.com> - - * src/display.c: (meta_display_begin_grab_op): don't forget to - initialize display->grab_old_window_stacking. Thanks to Sebastien - Bacher and the bleeding edge Ubuntu users for catching the - occasional crash this could cause so quickly, and for verifying - that the patch worked (I couldn't duplicate). Fixes #165093. - -2005-01-23 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.9.8 - -2005-01-23 Elijah Newren <newren@gmail.com> - - * NEWS: Metacity 2.9.5 unstable release - * README: there are more stable releases beyond 2.8.6... - -2005-01-23 Elijah Newren <newren@gmail.com> - - Restore original stacking when aborting an alt-esc window switch - operation. Fixes #123576. - - * src/display.c: (GRAB_OP_IS_WINDOW_SWITCH): new macro, - (meta_display_close): clear grab_old_window_stacking if non-NULL, - (event_callback): restore stack positions if alt-esc op cancelled - with button press, (meta_display_begin_grab_op): store the old - stacking positions, (meta_display_end_grab_op): free the old stack - positions - - * src/display.h: (struct _MetaDisplay): add a - grab_old_window_stacking list - - * src/keybindings.c: (process_tab_grab): restore stack positions - if alt-esc op cancelled with an errant key press - - * src/stack.c: (compare_just_window_stack_position): new - GCompareFunc function, (meta_stack_get_positions): get current - stack positions, (compare_pointers): new GCompareFunc function, - (lists_contain_same_windows): simple utility func to see if two - lists contains the same windows, (meta_stack_set_positions): new - function to set the positions of all the windows in the stack - - * src/stack.h: (meta_stack_get_postions, - meta_stack_set_positions): new functions - -2005-01-23 Elijah Newren <newren@gmail.com> - - Patch from John Paul Wallington to fix #163420. - - * src/window.c: (check_maximize_to_work_area): fix vertical - maximization for second screen - -2005-01-21 Elijah Newren <newren@gmail.com> - - * rationales.txt: Add a tracker bug for modal dialog issues - -2005-01-20 Elijah Newren <newren@gmail.com> - - * src/tabpopup.c (dimm_icon): use pixbuf, not dimmed_pixbuf (which - isn't defined yet). Fixes crash from #136666. - -2005-01-20 Vincent Noel <vnoel@cox.net> - - * src/screen.c: (meta_screen_ensure_tab_popup), - (meta_screen_ensure_workspace_popup): - * src/tabpopup.c: (meta_ui_tab_popup_new), (display_entry): - * src/tabpopup.h: Show labels in bold for windows that demand - attention. Fixes #164590. - -2005-01-18 Vincent Noel <vnoel@cox.net> - - * src/screen.c: (meta_screen_ensure_tab_popup), - (meta_screen_ensure_workspace_popup): - * src/tabpopup.c: (dimm_icon), (meta_ui_tab_popup_new), - (free_entry): - * src/tabpopup.h: In the tab task switcher popup, dim the window - icon and put its name between brackets when the window is - minimized. Fixes #136666. - -2005-01-11 Elijah Newren <newren@gmail.com> - - Correct highlighting of windows in workspace switcher popup. - Fixes #163450. - - * src/tabpopup.c (meta_select_workspace_expose_event): Remove race - between FocusIn/FocusOut events and the expose event by replacing - window->has_focus with - window==window->display->expected_focus_window. - -2005-01-09 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.9.5 - -2005-01-09 Elijah Newren <newren@gmail.com> - - * NEWS: Metacity 2.9.3 unstable release - -2005-01-09 Elijah Newren <newren@gmail.com> - - * src/display.c (meta_display_open): - * src/display.h (struct _MetaDisplay): - * src/window.c (meta_window_free, meta_window_client_message, - meta_window_notify_focus): - - Remove the hack from bug 128200; it isn't needed anymore with the - fix from bug #160470. - -2005-01-09 Elijah Newren <newren@gmail.com> - - Don't focus the panel on click. Fixes #160470 (and 100470 and - removes the need for the hack from 128200) - - * doc/how-to-get-focus-right.txt: Update section on focusing - non-decorated windows (specifically, DOCKS and DESKTOPS) - - * src/display.c (event_callback): don't focus dock windows on - click - -2005-01-06 Elijah Newren <newren@gmail.com> - - Make sure the save session dialog appears focused. Fixes #162983. - - * src/session.c (warn_about_lame_clients_and_finish_inter): Get a - timestamp by explicit request from Xserver, since none is - available otherwise. - -2005-01-06 Leena Gunda <leena.gunda@wipro.com> - - * src/window.c (meta_window_unmaximize): Restore the wireframe - rectangle co-ordinates to saved window co-ordinates. Fixes - bug #161236. - -2005-01-03 Thomas Fitzsimmons <fitzsim@redhat.com> - - * src/Makefile.am (install-data-local): Install schema data from - builddir not srcdir. - -2005-01-02 Elijah Newren <newren@gmail.com> - - Provide more documentation to make it easier for people to - contribute to Metacity. (#162646) - - * HACKING: Add lots of information to extend this document: more - on relevant standards and X properties, lots of information on - debugging and testing, and add a list of some other important - things to read; also move some information to - src/code-overview.txt and organize this file into sections. - - * doc/code-overview.txt: New file including some small parts from - the old HACKING file and lots of new stuff. This file gives a - brief overview of some of the bigger structures and files, with - guides for a variety of task categories providing places to start - looking in the code and things to look for. - -2004-12-28 Elijah Newren <newren@gmail.com> - - Allow users to move the window around immediately after - double-clicking to shade (#90290) - - * src/display.c (event_callback): only end the grab op if either - there is no frame or else the frame is not mapped - -2004-12-27 Elijah Newren <newren@gmail.com> - - Focus windows that manually position themselves too (fixes - #107347). - - * src/window.h (struct _MetaWindow): add a new - showing_for_first_time flag - - * src/window.c (meta_window_new_with_attrs): initialize - showing_for_first_time flag to !mapped, (meta_window_show): - replace did_placement with showing_for_first_time in the section - to decided whether to focus since did_placement isn't quite what - we want - -2004-12-27 Elijah Newren <newren@gmail.com> - - * src/display.c (meta_display_set_input_focus_window, - meta_display_focus_the_no_focus_window): Spew warning if - CurrentTime is passed to the function, but don't exit prematurely. - (fixes #162353) - -2004-12-24 Elijah Newren <newren@gmail.com> - - * src/window.c (meta_window_show_menu): Don't show menu if all - options are invalid (fixes #148915) - -2004-12-24 Elijah Newren <newren@gmail.com> - - * src/window.c (window_takes_focus_on_map): Fix error in - distinguishing < vs. <= introduced by the patch in #154598, - restructure code so that verbose log matches code better in order - ensure such mistakes are harder to make in the future (fixes - #162172) - -2004-12-24 Elijah Newren <newren@gmail.com> - - Thanks to mild7@users.sourceforge.net for this fix. - - * src/window.h: (META_WINDOW_IN_NORMAL_TAB_CHAIN): Excludes - windows with skip_taskbar hint set from the alt-tab list; they'll - appear in the ctrl-alt-tab list instead. (fixes #106249) - -2004-12-22 Elijah Newren <newren@gmail.com> - - Wrap XSetInputFocus, making display->expected_focus_window a - little more reliable (see #154598) - - * src/display.h: (struct _MetaDisplay): add a large comment about - the expected_focus_window, add a last_focus_time field, - (XSERVER_TIME_IS_BEFORE): new macro moved from window.c but fixed - for 64-bit systems, (meta_display_set_input_focus_window): new - function - - * src/display.c (meta_display_open): initialize last_focus_time, - add a comment about brokenness of trying to set intial focus - window, (meta_display_set_input_focus_window): new function that - wraps XSetInputFocus, - (meta_display_focus_the_no_focus_window): make this function - closer to a wrapping of XSetInputFocus for the no_focus_window. - - * src/window.c (XSERVER_TIME_IS_LATER): remove this macro in favor - of the improved one added to display.h - - * src/display.c (meta_display_open): - * src/window.c (meta_window_focus): - use meta_display_focus_the_no_focus_window and - meta_display_set_input_focus instead of XSetInputFocus - -2004-12-22 Elijah Newren <newren@gmail.com> - - * src/core.c (meta_core_user_lower_and_unfocus): - * src/display.c (meta_display_get_current_tab): - * src/stack.c (get_default_focus_window, meta_stack_list_windows): - * src/window.c (set_net_wm_state, meta_window_should_be_showing, - implement_showing, meta_window_activate, - meta_window_notify_focus): - * src/window.h: - * src/workspace.c (meta_workspace_list_windows): - - Rename meta_window_visible_on_workspace to - meta_window_located_on_workspace (whether or not the window was - showing wasn't taken into account, which made "visible" - confusing). Fixes #136314. - -2004-12-22 Elijah Newren <newren@gmail.com> - - Partially resolve the conflicting requirements of windows on - multiple workspaces and hidden being a global quantity for windows - (fixes bug 156182; the remainder of the work is bug 87531 and is a - libwnck issue) - - * src/display.c (event_callback): - * src/window.c (meta_window_visible_on_workspace, meta_window_unstick): - * src/workspace.c (meta_workspace_add_window, - meta_workspace_contains_window, - meta_workspace_queue_calc_showing): - * src/workspace.h: - - Remove meta_workspace_contains_window, replace with simple - comparison utilizing window->workspace - - * src/place.c (meta_window_place): - * src/window.c (meta_window_shares_some_workspace): - * src/window.h: - - Remove meta_window_shares_some_workspace, replace with a simple - comparison utilizing window->workspace - - * src/session.c (save_state), - * src/window.c (meta_window_new_with_attrs, - meta_window_apply_session_info, meta_window_free, - window_showing_on_its_workspace, - meta_window_change_workspace_without_transients, - meta_window_unstick, meta_window_set_current_workspace_hint, - meta_window_get_workspaces): - * src/window.h: - * src/workspace.c (meta_workspace_free, meta_workspace_add_window, - meta_workspace_remove_window): - - Only one workspace now - -2004-12-20 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.9.3 - -2004-12-20 Elijah Newren <newren@gmail.com> - - * NEWS: Metacity 2.9.2 unstable release - -2004-12-20 Elijah Newren <newren@gmail.com> - - * configure.in: re-add the note about Fibonacci sequence micro - version numbers that was lost with 2.8.5 - -2004-12-19 Elijah Newren <newren@gmail.com> - - Thanks to Baptiste Mille-Mathias for this fix. - - * src/metacity.schemas.in: Add a missing period at the end of a - sentence. - -2004-12-19 Elijah Newren <newren@gmail.com> - - When snap-moving, don't snap to transients of minimized windows - since they are hidden. Fixes #157180 - - * src/place.c (get_windows_on_same_workspace): make the logic to - determine hidden windows more thorough by calling - meta_window_should_be_showing() - - * src/window.c (meta_window_should_be_showing): rename this - function from window_should_be_showing and also export it, - (implement_showing): - s/window_should_be_showing/meta_window_should_be_showing/, - (idle_calc_showing): - s/window_should_be_showing/meta_window_should_be_showing/ - - * src/window.h (meta_window_should_be_showing): Add this function - to the list so that it can be used in src/place.c - -2004-12-19 Elijah Newren <newren@gmail.com> - - Focus the desktop when showing it. Fixes #159257. - - * src/display.c (event_callback): obtain a timestamp to pass to - meta_screen_show_desktop - - * src/keybindings.c (handle_toggle_desktop): obtain a timestamp to - pass to meta_screen_show_desktop - - * src/screen.c (meta_screen_show_desktop): add a timestamp - parameter, get the most recently used window of type DESKTOP (if - there is one) and focus it - - * src/screen.h (meta_screen_show_desktop): add a timestamp - parameter - -2004-12-19 Elijah Newren <newren@gmail.com> - - Thanks to ash@contact.bg for this fix. - - * po/POTFILES.in: Remove reference to metacity-properties.* files - since Alex removed them in his 2004-12-07 commit. - -2004-12-13 Elijah Newren <newren@gmail.com> - - * configure.in: post-release version bump to 2.9.2 that I forgot - to do last week (oops) - -2004-12-07 Alex Duggan <aldug@astrolinux.com> - - * configure.in: - * src/tools/Makefile.am: - - Remove deprecated capplet from GNOME 2.0 - - * src/tools/metacity-properties.c: - * src/tools/metacity-properties.desktop.in: - * src/tools/metacity-properties.glade: - * src/tools/metacity-properties.png: - - Removed from cvs - -2004-12-06 Elijah Newren <newren@math.utah.edu> - - * NEWS: Metacity 2.9.1 unstable release - -2004-12-06 Benjamin Kahn <xkahn@novell.com> - - * src/default_icon.png: Use a better default application - icon. Fixes bug #160373 - -2004-11-16 Marco Pesenti Gritti <marco@gnome.org> - - * src/Makefile.am: - - Fix build out of src directory. Bug #158325 - -2004-11-10 James Henstridge <james@jamesh.id.au> - - * Makefile.am (DISTCLEANFILES): remove intltool stuff on distclean. - - * src/themes/Makefile.am (uninstall-local): add uninstall rule. - - * src/Makefile.am (libmetacity_private_la_CFLAGS): set this - variable so that the files shared with metacity get compiled with - different names. - - * configure.in: use more modern macros in some places, and make - sure that $ACLOCAL_AMFLAGS is set so that rebuilds work better. - - * autogen.sh (conf_flags): use newer automake. - -2004-11-06 Vincent Untz <vincent@vuntz.net> - - * src/metacity.schemas.in: gnome-panel-screenshot was renamed to - gnome-screenshot - -2004-11-01 Elijah Newren <newren@math.utah.edu> - - * configure.in: bump version to 2.9.1 - -2004-11-01 Elijah Newren <newren@math.utah.edu> - - * NEWS, README: Metacity 2.9.0 (unstable release) - -2004-10-25 Elijah Newren <newren@math.utah.edu> - - Don't lower newly mapped windows when they're denied focus, if - they are transients of the focused window. Instead, defocus the - currently focused window. (fixes #151996). - - (Also, reenable focus stealing prevention and do a small spacing - cleanup) - - * src/window-props.c (init_net_startup_id): fix spacing - - * src/window.c (window_takes_focus_on_map): re-enable focus - stealing prevention, (meta_window_show): if the new window is - denied focus and is a transient of the currently focused window, - defocus the currently focused window but keep the transient on - top; remove some old code about transients and focus; make sure - that EnterNotify events won't accidentally focus the new window. - -2004-10-25 Elijah Newren <newren@math.utah.edu> - - Fix the alt-tab order--if the most recently used window is not - focused, start alt tabbing with that window instead of the one - after it (fixes #156251) - - * src/display.c (find_tab_forward): add a skip_first parameter, - (find_tab_backward): add a skip_last parameter, - (meta_display_get_tab_next): if a beginning window wasn't given - and the focused window isn't the tab chain, don't skip the MRU - window - -2004-10-22 Elijah Newren <newren@math.utah.edu> - - Update _NET_WM_STATE_HIDDEN so the pager on the panel will know - whether to display windows as visible or hidden (#105665) - - * src/screen.c (queue_windows_showing): Revert the - queue_windows_showing portion of the patch committed on 2004-10-16 - for #142198--it was an ill-advised optimization. - - * src/window.c (window_showing_on_its_workspace, - window_should_be_showing): split the old window_should_be_showing - into these two functions, (set_net_wm_state): hidden state is more - complex; use window_showing_on_its_workspace to determine the - correct value - -2004-10-20 Elijah Newren <newren@math.utah.edu> - - Patch from Soeren to fix the modifier key breakage introduced by - an Xorg change. (fixes #151554) - - * src/keybindings.c: include X11/XKBlib.h if available, - (handle_spew_mark): remove this unused function declaration, - (end_keyboard_grab): new function, uses XKB if available, - (process_tab_grab): use end_keyboard_grab to determine whether to - end the grab, (error_on_command): make key a const char *, - (process_workspace_switch_grab): use end_keyboard_grab to - determine whether to end the grab - -2004-10-19 Anders Carlsson <andersca@gnome.org> - - * src/frame.c: (meta_window_ensure_frame): - Don't try to use an ARGB visual at all if the depth isn't - 32-bit. This caused major slowdowns with Composite enabled. - -2004-10-16 Elijah Newren <newren@math.utah.edu> - - Make the "showing desktop" mode be per-workspace instead of - per-screen. (fixes #142198) - - * src/keybindings.c (handle_toggle_desktop): access - showing_desktop through the active workspace - - * src/screen.c (meta_screen_new): remove initialization of - screen->showing_desktop, - (meta_screen_update_showing_desktop_hint): rename and make not - static and access showing_desktop through the active workspace, - (queue_windows_showing): replace meta_display_list_windows() with - screen->active_workspace->windows, - (meta_screen_minimize_all_on_active_workspace_except): renamed - from meta_screen_minimize_all_except since it now only works on - the active workspace, (meta_screen_show_desktop, - meta_screen_unshow_desktop): access showing_desktop through the - active workspace - - * src/screen.h (struct _MetaScreen): remove showing_desktop field, - (meta_screen_minimize_all_on_active_workspace_except): rename from - meta_screen_minimize_all_except, - (meta_screen_update)_showing_desktop_hint): export this function too - - * src/window.c (maybe_leave_show_desktop_mode): access - showing_desktop through the active workspace and use new name for - meta_screen_minimize_all_on_active_workspace_except, - (window_should_be_showing): access showing_desktop through the - active workspace - - * src/workspace.c (meta_workspace_new): initialize - workspace->showing_desktop, (meta_workspace_activate_with_focus): - add note that old can be NULL, update showing_desktop_hint if - different on this workspace than the previous one - - * src/workspace.h (struct _MetaWorkspace): add showing_desktop - field - -2004-10-16 Elijah Newren <newren@math.utah.edu> - - * rationales.txt: Add new tracker bugs - -2004-10-15 Elijah Newren <newren@math.utah.edu> - - * src/keybindings.c (reload_keymap): Fix from Rob to correct - requested number of keycodes (#155247) - -2004-10-13 Elijah Newren <newren@math.utah.edu> - - Code cleanup - - * src/window.c (is_in_dock_group, docks_at_end_cmp, - shuffle_docks_to_end): removed functions, - (meta_window_notify_focus): no need to call is_in_dock_group or - shuffle_docks_to_end because of the patch from #120100 that was - committed. - -2004-10-13 Vincent Untz <vincent@vuntz.net> - - Add a keybinding to launch a terminal - - * src/keybindings.c: (handle_run_terminal): new function, - (error_on_generic_command): new function, (error_on_command): wrapper - around error_on_generic_command(), (error_on_terminal_command): new - function - - * src/metacity.schemas.in: add run_command_terminal key - - * src/prefs.[ch]: (meta_prefs_init): cache the terminal command and - register a gconf callback to update it, (change_notify): handle the - notification of terminal command changes, (meta_preference_to_string): - add the terminal command case, (update_terminal_command): new function, - (meta_prefs_get_terminal_command): new function, - (meta_prefs_get_gconf_key_for_terminal_command): new function - -2004-10-11 Rob Adams <readams@readams.net> - - * configure.in: bump version to 2.9.0. Add UNSTABLE warning. - -2004-10-11 Rob Adams <readams@readams.net> - - * NEWS, README: Metacity 2.8.6 (stable release) - -2004-10-08 Elijah Newren <newren@math.utah.edu> - - Fix middle-frame-click-to-lower focus inconsistency (#154601) - - * src/core.c (meta_core_user_lower_and_unfocus): focus the default - window in all focus modes, not just click-to-focus (EnterNotify - events will not handle this case for sloppy and mouse focus) - - * src/display.c (event_callback): replace window->has_focus with - window == display->expected_focus_window to avoid a race issue - -2004-10-08 Elijah Newren <newren@math.utah.edu> - - Alter the meaning of expected_focus_window; doesn't affect - current operation but assists in fixing some other bugs - (#154598) - - * src/display.c (meta_display_focus_the_no_focus_window): set the - expected_focus_window to NULL. - - * src/window.c (meta_window_notify_focus): don't NULL the - expected_focus_window when that window receives a FocusIn event - -2004-10-04 Elijah Newren <newren@math.utah.edu> - - * src/display.c (event_callback): if the root window gets focused, - set the focus to the default window; this fixes the - "focus-follows-mouse" behavior seen for click-to-focus mode after - cancelling log out (fixes #153220) - -2004-10-04 Elijah Newren <newren@math.utah.edu> - - Fix a variety of issues with autoraise (#134206) - - * src/display.h: (struct _MetaDisplay): add an autoraise_window - parameter - - * src/display.[hc] (meta_display_focus_the_no_focus_window): new - function, (meta_display_queue_autoraise_callback): new function, - (meta_display_remove_autoraise_callback): new function - - * src/display.c (meta_display_open): intialize - display->autoraise_window too, (meta_display_close): remove any - pending autoraise callback, (window_raise_with_delay_callback): - clear out auto_raise->display->autoraise_window too, - (event_callback): call meta_display_queue_autoraise_callback - instead of having the code inline, call - meta_display_focus_the_no_focus_window to handle focusing that - window - - * src/window.c (meta_window_focus): If there's a window with an - autoraise timeout that isn't the window being focused, remove the - autoraise timeout - - * src/workspace.c (meta_workspace_focus_default_window): If no - autoraise timeout is queued for the given window then queue one - now, call meta_display_focus_the_no_focus_window to handle - focusing that window, (meta_workspace_focus_mru_window): call - meta_display_focus_the_no_focus_window to handle focusing that - window - -2004-10-04 Elijah Newren <newren@math.utah.edu> - - * src/display.c (event_callback): When no window becomes focused, - focus the default window instead of punting to the - no_focus_window. Also, change the warning to a verbose - message--this will happen frequently due to brain-damage in the X - protocol. (see #125492) - -2004-10-04 Elijah Newren <newren@math.utah.edu> - - Fix a variety of focus race conditions in all focus modes, or at - least make them harder to trigger (fixes #152000) - - * src/core.[ch] (meta_core_user_lower_and_unfocus): add a - timestamp parameter; pass it along to - meta_workspace_focus_default_window - - * src/display.[ch] (meta_display_get_current_time_roundtrip): new - function - - * src/display.c (event_callback): pass a timestamp to the - meta_workspace_activate and meta_workspace_focus_default_window - function calls - - * src/frames.c (meta_frames_button_press_event): pass a timestamp - to meta_core_user_lower_and_unfocus - - * src/keybindings.c (handle_activate_workspace): pass a timestamp - to meta_workspace_activate, (process_workspace_switch_grab): pass - a timestamp to meta_workspace_focus_default_window and - meta_workspace_activate, (handle_toggle_desktop): pass a timestamp - to meta_workspace_focus_default_window, - (do_handle_move_to_workspace): pass a timestamp to - meta_workspace_activate_with_focus, (handle_workspace_switch): - meta_workspace_activate - - * src/screen.c (meta_screen_new): pass a timestamp to - meta_workspace_activate - - * src/window.c (meta_window_free): pass a timestamp to - meta_workspace_focus_default_window, (idle_calc_showing): don't - increment the focus sentinel here, (meta_window_minimize): pass a - timestamp to meta_workspace_focus_default_window, - (meta_window_client_message), pass a timestamp to - meta_workspace_focus_default_window - - * src/workspace.h (meta_workspace_activate): add timestamp - parameter, (meta_workspace_activate_with_focus): add timestamp - parameter, (meta_workspace_focus_default_window): add timestamp - parameter - - * src/workspace.c (meta_workspace_focus_mru_window): make this - function take a timestamp and use it for meta_window_focus or - XSetInputFocus, (meta_workspace_activate_with_focus): make this - function take a timestamp and pass it along to meta_window_focus - and meta_workspace_focus_default_window, - (meta_workspace_activate): make this function take a timestamp and - pass it to meta_workspace_activate_with_focus), - (meta_workspace_focus_default_window): make this function take a - timestamp, warn if its 0 but try to handle that case sanely, and - pass the timestamp on to meta_window_focus or - meta_workspace_focus_mru_window or XSetInputFocus - -2004-09-22 Elijah Newren <newren@math.utah.edu> - - * src/keybindings.c (process_workspace_switch_grab): Focus the - default window after the user dismisses the workspace switcher - popup (fixes #123803; note that an alternate fix was made - independently by David Baron for sloppy and mouse focus users) - -2004-09-22 Elijah Newren <newren@math.utah.edu> - - Fix some uninitialized variable errors reported by valgrind (see - #153338) - - * src/display.c (meta_display_open): initialize - display->grab_resize_timeout_id, and display->grab_have_keyboard - - * src/ui.c (meta_ui_create_frame_window): initialize attrs.width - and attrs.height - -2004-09-17 Elijah Newren <newren@math.utah.edu> - - * src/workspace.c (meta_workspace_focus_mru_window): Don't focus a - window that is minimized (fixes #147947) - -2004-09-17 Kjartan Maraas <kmaraas@gnome.org> - - * src/bell.c: (meta_bell_flash_screen): - * src/compositor.c: - * src/effects.c: (meta_effects_draw_box_animation): - * src/fixedtip.c: (meta_fixed_tip_show): - * src/frame.c: (find_argb_visual): - * src/frames.c: (unsigned_long_hash), (meta_frames_manage_window), - (meta_frames_apply_shapes): - * src/iconcache.c: (find_largest_sizes), (find_best_size): - * src/keybindings.c: (meta_spawn_command_line_async_on_screen): - * src/main.c: (main): - * src/menu.c: (meta_window_menu_new): - * src/prefs.c: (meta_prefs_get_visual_bell), - (meta_prefs_bell_is_audible), (meta_prefs_get_visual_bell_type), - (meta_prefs_get_action_double_click_titlebar), - (meta_prefs_get_auto_raise), (meta_prefs_get_auto_raise_delay), - (meta_prefs_get_reduced_resources): - * src/screen.c: (meta_create_offscreen_window): - * src/tabpopup.c: (meta_ui_tab_popup_get_selected): - * src/theme-parser.c: (meta_theme_load): - * src/theme.c: (meta_gtk_widget_get_font_desc): - * src/tools/metacity-mag.c: (mouse_press), (begin_area_grab): - * src/util.c: (meta_unsigned_long_hash): A load of fixes of issues - reported by sparse. Closes bug #152849 - -2004-09-15 Elijah Newren <newren@math.utah.edu> - - * src/display.c (event_callback): Remove some redundant code - regarding focusing the default window (#152117) - -2004-09-15 Elijah Newren <newren@math.utah.edu> - - Patch from Ken Harris in #135786 to focus a new default window - when lowering via middle-click on the frame. - - * src/core.[hc], src/frames.c: rename meta_core_user_lower to - meta_core_user_lower_and_unfocus - - * src/core.c (meta_core_user_lower_and_unfocus): if in - click-to-focus mode then also move the window to the back of the - mru list and focus the new default window for the active workspace - -2004-09-15 Elijah Newren <newren@math.utah.edu> - - Focus the no_focus_window if no suitable window is in the mru list - (should fix the almost contrived extra issue found in #147475) - - * doc/how-to-get-focus-right.txt: We no longer need to lie about - only focusing panels upon explicit request. - - * src/workspace.c: (meta_workspace_focus_top_window): removed this - function--it was more code than needed and was unreliable anyway, - (meta_workspace_focus_mru_window): if a suitable window isn't in - the mru list, focus the no_focus_window instead of calling - focus_top_window. - -2004-09-15 Elijah Newren <newren@math.utah.edu> - - Prevent focus inconsistencies by only providing one focus method - (fixes #151990) - - * src/screen.c (meta_screen_show_desktop): remove call to - meta_workspace_focus_top_window (it was merely focusing a window - that was going to be hidden anyway, and likely the one that - already had focus) - - * src/workspace.[hc]: remove meta_workspace_focus_mru_window and - meta_workspace_focus_top_window from workspace.h, make them static - functions in workspace.c - -2004-09-15 Elijah Newren <newren@math.utah.edu> - - Remove race condition for focus window choice on window close - followed by rapid mouse movement in sloppy and mouse focus modes - (partially fixes #152000) - - * src/window.c (meta_window_free): Don't increment the focus - sentinel for windows being freed, (idle_calc_showing): don't - increment the focus sentinel for windows being minimized - -2004-09-15 Elijah Newren <newren@math.utah.edu> - - Fix unwanted loss of focus to the mouse window when using keynav - (fixes #101190) - - * src/display.c (event_callback): Ignore EnterNotify events with - xcrossing.mode of either NotifyGrab or NotifyUngrab - -2004-09-15 Elijah Newren <newren@math.utah.edu> - - Focus correct window after minimizing via the tasklist (fixes - #128200; see also #107681) - - * src/display.h (struct _MetaDisplay): track the - previously_focused_window - - * src/display.c (meta_display_open): initialize - previously_focused_window - - * src/window.c (meta_window_free): clear the - previously_focused_window if it's being freed, - (meta_window_client_message): if we get a request to minimize the - previously_focused_window and the focus_window is a dock or the - desktop, focus the default window, (meta_window_notify_focus): - update the previously_focused_window - -2004-09-13 Rob Adams <readams@readams.net> - - * configure.in: post-release increment - -2004-09-13 Rob Adams <readams@readams.net> - - * configure.in: bump version number - - * NEWS: 2.8.5 release - - * README: 2.8.5 release - -2004-09-14 Gora Mohanty <gmohanty@cvs.gnome.org> - - * configure.in: Added 'or' to ALL_LINGUAS. - -2004-09-07 Elijah Newren <newren@math.utah.edu> - - Add a new write-up on making window focus consistent (see #152004) - - * doc/how-to-get-focus-right.txt: New document - - * rationales.txt: Remove references to focus bugs, instead point - to doc/how-to-get-focus-right.txt - -2004-09-06 Elijah Newren <newren@math.utah.edu> - - * rationales.txt: Add bugs regarding window focus - -2004-08-29 Elijah Newren <newren@math.utah.edu> - - * NEWS: 2.8.4 release - -2004-08-29 Elijah Newren <newren@math.utah.edu> - - * src/window.c (window_takes_focus_on_map): Disable - focus-stealing-prevention for now; there are still some issues and - hard code freeze is tomorrow...so this will have to wait until - Gnome 2.10. - -2004-08-27 Havoc Pennington <hp@redhat.com> - - * src/compositor.c (meta_compositor_new): disable NameWindowPixmap - stuff always for now, it seemed kind of busted - (paint_screen): don't grab the server during repaint, adds to the - speed, though only slightly. - - * src/frames.c (meta_frames_set_window_background): factor out all - the set_background stuff to one function; disable setting - background to transparent, because it breaks existing themes. We - need to add a flag in the theme XML file to say "start me with a - transparent background" - -2004-08-27 Elijah Newren <newren@math.utah.edu> - - Prevent an assertion failure that can occur after increasing the - number of workspaces; also fix a warning and stacking order when a - window is denied focus (fixes #150615) - - * src/window.c (meta_window_stack_just_below): the position of the - window should be set equal to that of the one we want to be below, - not 1 lower than that number - - * src/workspace.c (maybe_add_to_list): new function to add - on_all_workspace windows to an mru_list, (meta_workspace_new): - call maybe_add_to_list for all windows on the screen in order to - initialize the mru_list - -2004-08-26 Havoc Pennington <hp@redhat.com> - - * src/frame.c: delete extra copy of find_argb_visual so things - compile - - * src/compositor.c (HAS_NAME_WINDOW_PIXMAP): copy the - XCompositeNameWindowPixmap() stuff from xcompmgr, though I can't - say I really know what it's supposed to help with (painting the - window border?) - -2004-08-26 Havoc Pennington <hp@redhat.com> - - * src/frame.c, src/theme.c: couple of cosmetic tweaks from - resolving my local patch with the bugzilla patch from the 8-19 - entry below - -2004-08-26 Havoc Pennington <hp@redhat.com> - - * configure.in: move the have_xrender variable initialization up - in the file since it can be set as part of composite check - -2004-08-19 Havoc Pennington <hp@redhat.com> - - Fixes from Rich Wareham - - * src/display.h (struct _MetaDisplay): add render extension check - to the display - - * src/display.c: check for render - - * configure.in: don't build compositing manager by default, don't - want any nasty surprises; check for render separately from - compositing manager - - * src/frame.c: use an ARGB visual when available for the window - frame, so we can be all cool-ass - -2004-08-25 Elijah Newren <newren@math.utah.edu> - - Make dialogs that Metacity shows follow focus-stealing-prevention - conventions. (fixes one issue in #149028; see comments 47-54) - - * src/delete.c (delete_ping_reply_func, - delete_ping_timeout_func): Make callback functions take a - timestamp arg, (delete_ping_timeout_func): pass the timestamp to - metacity-dialog - - * src/display.c (meta_display_ping_timeout): add a timestamp to - the call to the ping_timeout_func, (meta_display_ping_window, - process_pong_message): add a timestamp to the call to the - ping_reply_func - - * src/display.h (MetaWindowPingFunc typedef): add a timestamp to - this function typedef - - * src/keybindings.c (error_on_command): require a timestamp and - pass the timestamp on to metacity-dialog, (handle_run_command): - pass a timestamp to error_on_command - - * src/metacity-dialog.c (copy_of_gdk_x11_window_set_user_time): - new function (temporary; only for use while using gtk+-2.4), - (kill_window_question, warn_about_no_sm_support, - error_about_command): make these functions take a timestamp and - call copy_of_gdk_x11_window_set_user_time, (main): require the - first two args to the program to be "--timestamp <timestamp>" - - * src/session.c (warn_about_lame_clients_and_finish_inter): pass a - timestamp of 0 to metacity-dialog to prevent focus (it's a popup - not generated by and kind of user request). - -Fri Aug 20 12:54:12 2004 Soeren Sandmann <sandmann@daimi.au.dk> - - * src/display.c (meta_display_end_grab_op): Move wireframe code - before grab is released to prevent endless loops with fullscreen - windows. - -2004-08-18 Havoc Pennington <hp@redhat.com> - - * src/display.h (struct _MetaDisplay): track the last_xor_rect - separately from the current window size, and then use that to - paint the wireframe including the frame, and taking into - account shaded windows. - - * src/window.c (meta_window_get_xor_rect): new function to compute - the xor rect; it is not really 100% right, because it uses the - frame dimensions from the window at the start of the move/resize. - But probably won't break in practice. - -2004-08-17 Christian Rose <menthos@menthos.com> - - * configure.in: Added "bs" to ALL_LINGUAS. - -2004-08-16 Kjartan Maraas <kmaraas@gnome.org> - - * configure.in: Added nb to ALL_LINGUAS. - -2004-08-15 Rob Adams <readams@readams.net> - - * configure.in: Bump version to 2.8.4 - -2004-08-15 Rob Adams <readams@readams.net> - - * NEWS: 2.8.3 release - -2004-08-15 Rob Adams <readams@readams.net> - - * src/windows.c (meta_window_update_struts): use height and - top/bottom struts to compute gap (copy/paste bug). - -2004-08-15 Rob Adams <readams@readams.net> - - * src/window.c (meta_window_update_struts): Allow struts larger - than 1/2 the screen width/height, as long as there's a minimum - sized gap between them. Patch from Bill Haneman <billh@gnome.org> - for bug #144126. - -2004-08-13 Gurban M. Tewekgeli <gmtavakkoli@yahoo.com> - * po/tk.po: Added Turkmen translation. - * configure.in: Added "tk" to ALL_LINGUAS. - -Mon Aug 9 05:38:33 2004 Soeren Sandmann <sandmann@daimi.au.dk> - - * src/effects.c (graphics_sync): New function. - * src/effects.c (effects_draw_box_animation_timeout): Use it here - to synchronize with the hardware between each frame. - -2004-08-08 Rob Adams <readams@readams.net> - - * src/window.c (meta_window_move_resize_internal): Add #ifdef - around XSYNC code; fixes compile problem if XSYNC is disabled. - Path for #149314 from Peter O'Shea and independently Mike Castle. - -Sun Aug 8 14:20:00 2004 Soeren Sandmann <sandmann@daimi.au.dk> - - * src/frame.c (meta_frame_set_screen_cursor): Flush after setting - cursor. (Rest of #149413). - -2004-08-07 Elijah Newren <newren@math.utah.edu> - - * src/display.c (event_callback): activating the current workspace - should be a no-op. This prevents a race condition in focus window - choice when activating a window via the taskbar. Fix for #149589. - -2004-08-07 Elijah Newren <newren@math.utah.edu> - - * src/window.c, src/window.h: Revert Rob's 2004-07-31 patch that - ignored net_wm_user_time when unminimizing a window - - * src/window.c (meta_window_activate): If a nonzero timestamp is - passed, update the window's net_wm_user_time accordingly. (see - comments 102-108 of bug 118372) - -2004-08-07 Rob Adams <readams@readams.net> - - Remove some extraneous items that could sometimes appear in the - window menu. Fix for #144493. - - * src/menu.c (menuitems): Change the second separator to key on - whether there are any workspaces. - (meta_window_menu_new): use NULL label instead of 0 op to identify - separator - - * src/window.c (meta_window_show_menu): Change the conditions on - the directions to take into account "holes" in the workspace - layout and also only set META_MENU_OP_WORKSPACES when there's more - than one workspace. - -2004-08-07 Havoc Pennington <hp@redhat.com> - - * src/screen.c (meta_screen_set_cursor): add XFlush() after - setting cursor, #149413 - -2004-08-06 Elijah Newren <newren@math.utah.edu> - - * src/display.c (event_callback): Focusing a window upon unshowing - the desktop in various ways (panel applet or keybinding) was - inconsistent for sloppy and click focus modes. Fix this by - calling meta_workspace_focus_default_window after unshowing the - desktop via a _NET_SHOWING_DESKTOP message. (resolves #149543) - -2004-08-06 Elijah Newren <newren@math.utah.edu> - - * src/workspace.c (meta_workspace_focus_default_window): prevent - keyboard from "getting locked" upon workspace switch, by making - sure that the no_focus_window has focus if no other window does. - (fixes #147475) - -2004-08-05 Elijah Newren <newren@math.utah.edu> - - Have newly mapped windows that are denied focus appear after the - focused window in the alt-tab list. This allows one to switch to - such a window with a single alt-tab press. (fixes #149366) - - * src/window.c (ensure_mru_position_after): new function, - (meta_window_show): If newly mapped window is denied focus, call - ensure_mru_position_after to make the window appear after the - focus window in the mru list. - -2004-08-05 Elijah Newren <newren@math.utah.edu> - - * src/window.c (meta_window_stick): prepend window to mru list - instead of appending, since making the window sticky should imply - that it is the most recently used, not the least recently. (fixes - #149369) - -2004-08-04 Elijah Newren <newren@math.utah.edu> - - * configure.in: post-release version bump (2.8.3) that I forgot to - do yesterday. - -2004-08-03 Elijah Newren <newren@math.utah.edu> - - Released 2.8.2 - - * NEWS, README: update - -2004-08-02 Elijah Newren <newren@math.utah.edu> - - Fix some bugs (reported in #120100) regarding the focus window - when using the workspace switcher. - - * src/display.c (event_callback): When switching workspaces due to - a _NET_CURRENT_DESKTOP message, make sure to focus the default - window as well. - - * src/workspace.c (meta_workspace_focus_default_window, - meta_workspace_focus_mru_window): Make DOCK or DESKTOP windows - have lower priority than others when choosing a window to focus. - (For the former function, this means don't focus them at all; for - the latter, this means only focus them (via the - meta_workspace_focus_top_window call) if no other mru window can - be found.) - -2004-07-31 Rob Adams <readams@readams.net> - - Fix bug that caused windows to not be focused on unminimizing - because of user time support. - - * src/window.c (meta_window_new_with_attrs): initialize - focus_despite_user_time bit - (window_takes_focus_on_map): focus if focus_despite_user_time - despite user time, interestingly enough - (meta_window_show): reset focus_despite_user_time after showing - - * src/window.h (_MetaWindow): add focus_despite_user_time bit - -2004-07-31 Rob Adams <readams@readams.net> - - Fix some support for EWMH hints, and fix USER_TIME support to - include the DEMANDS_ATTENTION hint. Also includes some code for - implementing _NET_RESTACK_WINDOW and _NET_MOVERESIZE_WINDOW, but - this is disabled pending feature thaw. - - * COMPLIANCE: update with new information - - * src/display.c (meta_display_open): add new hints to list - - * src/display.h (_MetaDisplay): Add new atoms to struct - - * src/screen.c (set_supported_hint): update the list of support - hints. - (set_desktop_viewport_hint): new function sets the viewport hint - to (0,0) as required by the spec for WMs with no viewport support. - (set_desktop_geometry_hint): new function to set the desktop size - hint to the size of the display, since we don't implement large - desktop support, as required by the spec. - (meta_screen_resize): update the geometry hint on screen resize - - * src/window.c (meta_window_new_with_attrs): Initialize - demands_attention state - (set_net_wm_state): Set demands_attention hint in the window state - (meta_window_show): If we don't pop up a window because of - USER_TIME, set DEMANDS_ATTENTION on the window. - (meta_window_focus): When a window receives focus, remove - DEMANDS_ATTENTION hint - (meta_window_client_message): Allow other apps to set - DEMANDS_ATTENTION on a window. Also, if the _NET_ACTIVE_WINDOW - hint includes a timestamp, use it. - (update_net_wm_state): Read DEMANDS_ATTENTION state also - - * src/window.h (_MetaWindow): add wm_state_demands_attention bit. - -2004-07-22 Rob Adams <readams@readams.net> - - * src/metacity.schemas.in: Add trailing quotes to keybinding - explanation text. Patch from Emil Soleyman-Zomalan. - -Fri Jun 25 17:41:53 2004 Soeren Sandmann <sandmann@daimi.au.dk> - - * configure.in: Require startup-notification 0.7 - -2004-06-25 Rob Adams <readams@readams.net> - - * COMPLIANCE: indicate that _NET_WM_USER_TIME is now supported - -2004-06-24 Elijah Newren <newren@math.utah.edu> - - * src/keybindings.c: (handle_toggle_desktop): Choose correct - window to focus when "un-showing" the desktop. Fixes #144900. - -2004-06-24 Elijah Newren <newren@math.utah.edu> - - Make choice of focus window be consistent for each focus mode. - Fixes #135810. - - * src/delete.c: (meta_window_delete): In some #if 0'ed code, - replace meta_workspace_focus_mru_window with - meta_workspace_focus_default_window (just in case the code becomes - un-#if 0'ed out). - - * src/screen.c, src/screen.h: Change - meta_screen_focus_mouse_window to meta_screen_get_mouse_window, - and don't focus the window when found but rather return it. - - * src/window.c: (meta_window_free, meta_window_minimize): replace - meta_workspace_focus_mru_window with - meta_workspace_focus_default_window. - - * src/workspace.c: (meta_workspace_focus_default_window): Focus - appropriately for the given focus method: - click-to-focus: focus MRU window (== toplevel window) - sloppy focus: focus the window under the pointer if there is - such a window, otherwise focus the mru window - mouse focus: focus the window under the pointer if there is - such a window, otherwise don't focus anything - -2004-06-24 Elijah Newren <newren@math.utah.edu> - - * src/window.c: Avoid a race condition on the choice of window to - focus after the previously focused window gets closed or - minimized. Fixes #131582. - -2004-06-24 Elijah Newren <newren@math.utah.edu> - - * src/metacity.schemas.in: make naming for "move a window"/"move - the window"/"move window" more consistent. Patch from Michael - Terry for #142235. - -2004-06-24 Elijah Newren <newren@math.utah.edu> - - * src/session.c: Change meta_warning to meta_topic on failure to - connect to a session manager. Fixes #136218. - -2004-06-17 Elijah Newren <newren@math.utah.edu> - - Add support for _NET_WM_USER_TIME - - * src/display.c: - (meta_display_open): Add _NET_WM_USER_TIME to atom_names[], - (event_callback): Manually set _NET_WM_USER_TIME upon KeyPress - (doesn't work since keyboard isn't grabbed) and ButtonPress (does - work), this is just a fallback for applications that don't update - this themselves. - - * src/display.h: (struct _MetaDisplay): Add atom_net_wm_user_time field - - * src/screen.c: (meta_screen_apply_startup_properties): Check for - TIMESTAMP provided from startup sequence as well. - - * src/stack.c: - s/meta_window_set_stack_position/meta_window_set_stack_position_no_sync/, - (meta_window_set_stack_position): New function which calls the - meta_window_set_stack_position_no_sync function followed immediately - by calling meta_stack_sync_to_server. - - * src/window-props.c: - (init_net_wm_user_time), (reload_net_wm_user_time): new functions, - (reload_wm_hints): also load atom_net_wm_user_time - - * src/window.c: - new XSERVER_TIME_IS_LATER macro (accounts for timestamp wraparound), - (meta_window_new_with_attrs): add timestamp attributes, - (window_takes_focus_on_map): use TIMESTAMP from startup - notification and _NET_WM_USER_TIME to decide whether to focus new - windows, - (meta_window_show): if app doesn't take focus on map, place it - just below the focused window in the stack - (process_property_notify): check for changes to _NET_WM_USRE_TIME, - (meta_window_stack_just_below): new function - - * src/window.h: - (_MetaWindow struct): new fields for initial_timestamp, - initial_timestamp_set, net_wm_user_time_set, and net_wm_user_time, - (meta_window_stack_just_below): new function - -2004-06-21 Anders Carlsson <andersca@gnome.org> - - * src/common.h: - * src/menu.c: (menu_closed), (activate_cb): - * src/window.c: (menu_callback): - Add a timestamp argument to menu functions and - use it in meta_window_delete. - -2004-06-21 Anders Carlsson <andersca@gnome.org> - - * src/window.c: (meta_window_client_message): - Get the timestamp from the client message. - -Sat Jun 19 02:21:08 2004 Soeren Sandmann <sandmann@daimi.au.dk> - - Fix bug 143333, support for update counter spec, and 109362, - schedule compensation events when events are ignored. - - * src/display.c (meta_display_open): Add _NET_WM_SYNC_REQUEST and - _NET_WM_SYNC_REQUEST_COUNTER atoms. Remove the old - METACITY_SYNC_COUNTER stuff. - (meta_display_begin_op): Setup the sync counter - - * src/xprops.c, src/xprops.h, src/window-props.c, src/display.h: - Add new atoms. - - * src/window.c (send_sync_request): new function. - (meta_window_move_resize_internal): send a sync request before - resizing. - (check_move_resize_frequence): Rework logic to also check the SYNC - case. If an event is ignored return the remaining time. - (update_resize_timeout): Timeout that gets called when a - compensation event is scheduled. - (uddate_resize): schedule compensation events when an event is - ignored. - (meta_window_handle_mouse_grap_op_event): When an alarm is - received and sync was turned off, turn it back on. - - * src/window.h (struct MetaWindow) Add some variables - -2004-06-16 Havoc Pennington <hp@redhat.com> - - * configure.in: bump version, add the UNSTABLE note - - * Branch off GNOME 2.6, we are now officially unstable - -2004-06-04 Jeff Waugh <jdub@perkypants.org> - - * src/metacity.schemas.in: Set titlebar_uses_system_font = false. The - previous default was almost violent in its lack of appreciation for - human beings. In fact, this entire setting should probably be removed, but - for now, let's just fix the default. Permission granted by Havoc. - -2004-05-04 Elijah Newren <newren@math.utah.edu> - - * configure.in: 2.8.1 - - * NEWS: update - -2004-05-02 Rob Adams <readams@readams.net> - - * src/metacity-dialog.c (warn_about_no_sm_support): make the no sm - support warning dialog resizable, since the default GTK warning - dialog not has default not resizable. Fix for #141672 from - Olivier Crete. - -2004-04-29 Rob Adams <readams@readams.net> - - * src/prefs.c (change_notify): Add a value type check for the - visual bell/audible bell gconf settings. Patch from Jarrod - Johnson for #141409. - -2004-04-19 Mark McLoughlin <mark@skynet.ie> - - Syncing across this change from libwnck. - Patch from Neil Muller <neil@dip.sun.ac.za> in bug #133979. - - * src/iconcache.c: (find_largest_sizes), (find_best_size): - Don't down-size nitems from a gulong to an int. Fixes a - crash with enlightenment, apparently. - -2004-04-16 Iñaki Larrañaga <dooteo@euskalgnu.org> - - * configure.in: Added "eu" (Basque) to ALL_LINGUAS. - -2004-04-15 Elijah Newren <newren@math.utah.edu> - - * src/display.c: Prevent unwanted grab op from occurring. - Previously, for some people under certain conditions, clicking and - releasing the mouse button rapidly enough would result in Metacity - starting a move operation due to ignoring the button release. - This should fix that problem (it does for me). See bug 136587. - -2004-04-11 Rob Adams <readams@readams.net> - - * configure.in: Make the --enable-xinerama switch work properly. - Fix for #138562 from foser@gentoo.org. - -2004-04-09 Guntupalli Karunakar <karunakar@freedomink.org> - - * configure.in: Added "gu" (Gujarati) to ALL_LINGUAS. - -2004-03-27 Tõivo Leedjärv <toivo@linux.ee> - - * configure.in: Added et to ALL_LINGUAS. - -2004-03-24 Guntupalli Karunakar <karunakar@freedomink.org> - - * configure.in: Added "pa" (Punjabi) to ALL_LINGUAS. - -2004-03-21 Havoc Pennington <hp@redhat.com> - - * configure.in: 2.8.0 - - * NEWS: update - -2004-03-07 Elijah Newren <newren@math.utah.edu> - - * rationales.txt: Bring up to date (see bug 136252). - -2004-03-07 Havoc Pennington <hp@redhat.com> - - * configure.in: 2.7.1 - -2004-03-04 Paisa Seeluangsawat <paisa@users.sf.net> - - * configure.in: Added "th" (Thai) to ALL_LINGUAS. - -2004-03-01 Rob Adams <readams@readams.net> - - * src/stack.c (compute_layer): don't promote due to transiency; we - handle that elsewhere now. - (ensure_above): perform layer promotion here as well as stack - position promotion. Note that this means that we need to do stack - constraints now on layer change now. - (get_maximum_layer_of_ancestor): remove function - (max_layer_func): remove function - (MaxLayerData): remove struct - -2004-02-28 Rob Adams <readams@readams.net> - - Revert 2/27 patch for layer promotion. - -2004-02-27 Rob Adams <readams@readams.net> - - * src/window.c (meta_window_notify_focus): only move on MRU list - if the window belongs on the workspace, since the FocusIn event - could be for a window whose workspace we've since switched away - from. Possible fix for #122016. - - * src/workspace.c (meta_workspace_contains_window): search for the - workspace in window->workspaces rather than the window in - workspace->windows. Since the number of workspaces is at most 36, - this is a O(1) lookup rather than a O(n) lookup. Sorry; couldn't - resist. - -2004-02-27 Rob Adams <readams@readams.net> - - * src/metacity.schemas.in: Change - move_to_workspace_left/right/up/down keybindings to - <Control><Alt><Shift> arrow to avoid conflicting with new - keybindings in spacial nautilus. - -2004-02-27 Rob Adams <readams@readams.net> - - Handle layer promotion of transient descendants of layer-promoted - windows to also be layer promoted, using a simple iterative - algorithm. - - * src/stack.c (compute_layer): change name to promote_layer, and - convert to simply perform any necessary layer promotion without - computing the standalone layer. - (max_layer_func): use window->layer instead of - get_standalone_layer - (get_maximum_layer_of_ancestor): use window->layer instead of - get_standalone_layer - (meta_stack_ensure_sorted): implement iterative algorithm, - explained in a long comment. - - * src/window.h: add a tmp_layer field used by stack.c for - determining if the stack is dirty or not, since maintaining this - information in meta_stack_ensure_sorted is no longer practical. - -2004-02-23 Rob Adams <readams@readams.net> - - Add my copyright notice to a number of files on which it should - already exist. - - * src/window.c (meta_window_notify_focus): modify code to move to - front of MRU list so that we can have an assert that it was there - in the first place. This code may be causing some crashes. See - #131196. - -2004-02-22 Christian Rose <menthos@menthos.com> - - * configure.in: Added "en_CA" to ALL_LINGUAS. - -2004-02-19 Rob Adams <readams@readams.net> - - * src/prefs.h: remove trailing comma in MetaKeyBindingAction enum. - Fix for #134868 thanks to bugzilla-gnome@thewrittenword.com. - -2004-02-16 Rob Adams <readams@readams.net> - - * src/window.c (update_move): reset drag state after shaking loose - or reattaching. Fix for #132625. - -2004-02-15 Anders Carlsson <andersca@gnome.org> - - * src/menu.c (meta_window_menu_new): Actually translate a message, - don't just mark it for translation. - -2004-02-14 Elijah Newren <newren@math.utah.edu> - - * src/workspace.c: When moving a window to a different workspace, - prepend it to the mru list insted of appending it. Fixes #134368. - -2004-02-14 Rob Adams <readams@readams.net> - - If we're moving a window and receive a _NET_CURRENT_DESKTOP - message indicating a workspace switch, bring along the drag window - to the new workspace, solving a potentially weird bug where the - window would be lost on the old workspace. This also makes it - possible to implement edge flipping in an external program with - just a few lines of code. Patch for #131630 from ed@catmur.co.uk. - - * src/keybindings.c (switch_to_workspace): remove function -- no - longer needed. - (handle_activate_workspace): call meta_workspace_activate instead - of switch_to_workspace - - * src/workspace.c (meta_workspace_activate_with_focus): if we're - in a move grab op, bring along the drag window. - -2004-02-14 Rob Adams <readams@readams.net> - - * configure.in: Add configure option to not even try using - xinerama, to make metacity buildable on systems with no shared - library version of the xinerama libraries. Patch for #134203 from - Julio M. Merino Vidal. - -2004-02-01 Rob Adams <readams@readams.net> - - * COMPLIANCE: Bring up to date with current draft EWHM. - -2004-01-27 James M. Cape <jcape@ignore-your.tv> - - * src/themes/Esco/metacity-theme-1.xml: Use the 'utility' frame - for dialogs too. - -2004-01-24 James M. Cape <jcape@ignore-your.tv> - - * src/themes/Esco/metacity-theme-1.xml: Updated this theme. - -2004-01-21 Elijah Newren <newren@math.utah.edu> - - * src/screen.c (set_supported_hint): Removed some duplicate - entries. - -2004-01-17 Rob Adams <readams@readams.net> - - * src/metacity.schemas.in: Default binding removed for - toggle_shaded, since we don't have anything in the graphical UI - for it any more. - -2004-01-17 Rob Adams <readams@readams.net> - - * src/window.c (meta_window_show_menu): Don't show - left/right/up/down if a window is sticky. Make "On Top" - insensitive for docks, splash screens, and desktops since it has - no effect anyway. - -2004-01-10 Rob Adams <readams@readams.net> - - * src/metacity.schemas.in: update default - action_double_click_titlebar to be toggle_maximize instead of - toggle_shade. See #131126. - -2004-01-10 Rob Adams <readams@readams.net> - - * src/constraints.c (meta_window_constrain): if we maximize after - placement, and the window is too big to fix in the work area, - define a sane saved_rect approximately with dimensions - three-quarters approximately three quarters the size of the work - area. This avoids the problem where large windows would - unmaximize and actually get bigger. See #93590. - -2004-01-09 Thomas Fitzsimmons <fitzsim@redhat.com> - - Add _NET_FRAME_EXTENTS and _NET_REQUEST_FRAME_EXTENTS. - - * src/display.c: include xprops.h - (process_request_frame_extents): new function - (meta_display_open): add _NET_FRAME_EXTENTS and - _NET_REQUEST_FRAME_EXTENTS atoms - (event_callback): handle frame extents message - - * src/display.h (struct _MetaDisplay): add atom_net_frame_extents - and atom_net_request_frame_extents - - * src/theme.c (meta_pango_font_desc_get_text_height): make font_desc - parameter const - - * src/ui.c: include prefs.h - (meta_ui_theme_get_frame_borders): new function - - * src/window.c (update_net_frame_extents): new function - (meta_window_move_resize_internal): update frame extents - property when frame geometry changes - - * src/screen.c (set_supported_hint): add atom_net_frame_extents - and atom_net_request_frame_extents - -2004-01-09 Calum Benson <calum.benson@sun.com> - - * src/themes/Atlanta/metacity-theme-1.xml: - - Ensure Atlanta window buttons get larger when using large - print themes. Fixes #123469. - -2003-01-04 Rob Adams <readams@readams.net> - - Maintain the button grab for sloppy and mouse focus all the time. - This fixes a number of problem introduced by trying to drop the - grab; we now do this only for click to focus mode. This has the - unfortunate effect that #102209 reappears for sloppy and mouse - focus, but this seems unavoidable, because of limitations in the X - protocol. See #115072. - - * src/display.c (meta_display_grab_focus_window_button): #if 0 the - section on not grabbing unless in click-to-focus mode. - - * src/window.c (meta_window_notify_focus): drop focus button grab - on FocusIn and acquire it on FocusOut only when in click-to-focus - mode. - -2004-01-03 Robert Sedak <robert.sedak@sk.htnet.hr> - - * configure.in: Added "hr" in ALL_LINGUAS. - -2003-01-02 Rob Adams <readams@readams.net> - - * README: Update reference to EWMH. - - * HACKING: Add a reference to COMPLIANCE and to the ICCCM and - EWHM. - -2003-12-25 Havoc Pennington <hp@redhat.com> - - * src/compositor.c (process_reparent): handle ReparentNotify, and - add a lot of debug output. - -2003-12-25 Havoc Pennington <hp@redhat.com> - - * src/compositor.c (meta_compositor_process_event): change to - track all children of the root window, not only mapped children; - this keeps us from losing track of the stacking order - - * src/display.c (event_callback): don't do any of the compositor - event handling inline, do it all in compositor.c - -2003-12-21 Rob Adams <readams@readams.net - - * src/main.c (main): fix minor punctuation error in a string. Fix - for #129805. - -2003-12-20 Rob Adams <readams@readams.net> - - Reorganize the window menu according to discussion on #110904. - The workspace name mnemonic chunk of the patch is thanks to - Jonathan Blandford. - - * src/common.h: add MENU_OP_ABOVE, MENU_OP_UNABOVE, MENU_UP_MOVE_TO_* - menu ops. - - * src/core.c (meta_core_get_menu_accelerator): add accelerator for - the new menu ops. - - * src/menu.c: add checked attribute in _MenuItem struct to display - a checkmark next to a menu item. Add the new menu items to - menuitems. - (get_workspace_name_with_accel): Add mnemonics even to renamed - workspaces. - (menu_item_new): provide support for the checked attribute - (meta_window_menu_new): construct new submenu for workspace - switching. - - * src/window.c (menu_callback): implement support for the new menu - ops. - (meta_window_show_menu): don't use the OP_*SHAPE operations, and - compute which of the OP_MOVE_TO_* ops should be used for the - current workspace and workspace layout. Add the OP_*ABOVE - operations. - -2003-12-20 Arafat Medini <lumina@silverpen.de> - - * configure.in: Added Arabic locale "ar" to ALL_LINGUAS - -2003-12-17 Rob Adams <readams@readams.net> - - * src/display.c (meta_display_open): initialize - grab_wireframe_active to FALSE. Fix for #128090. - -2003-12-17 Rob Adams <readams@readams.net> - - * src/tabpopup.c (meta_ui_tab_popup_new): Don't try to call - utf8_strndup on a null title for an entry. Fix for #128566. - - * src/workspace.c (meta_workspace_free): Call g_list_free on the - mru_list, since with sticky windows that MRU list could well not - be emtpy. See #122016. - -2003-12-13 Rob Adams <readams@readams.net> - - * src/window.c (meta_window_new_with_attrs): set on_all_workspaces - in all cases _before_ adding to the workspaces, so that windows - initially on all workspaces are added correctly to the MRU lists. - Fix for #120907. - - * src/workspace.c (meta_workspace_add_window): handle sticky - windows so that we add to add mru lists if needed - (meta_workspace_remove_window): handle sticky windows so that they - are removed from all mru lists if needed. - -2003-12-12 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_free): unstick window to get it out of - mru_list it should not be in; assert that window has been removed - from all mru_list. Perhaps fixes #122016 crash. - -2003-11-29 Havoc Pennington <hp@redhat.com> - - * fix up compositing manager to somewhat work - -2003-11-26 Rob Adams <readams@readams.net> - - * COMPLIANCE: fix a couple of minor typos. - -2003-11-24 Havoc Pennington <hp@redhat.com> - - * src/compositor.c (meta_compositor_new): fix the extension checks - -2003-11-24 Havoc Pennington <hp@redhat.com> - - * src/iconcache.c (meta_icon_cache_init): init prev_mask field - - * src/window.c (meta_window_new_with_attrs): init xgroup_leader - prior to use - -2003-11-24 Havoc Pennington <hp@redhat.com> - - * src/display.c (meta_display_begin_grab_op): add an event_serial - argument and use it when the pointer is already grabbed - automatically on the button press. May fix bug #126871 - -2003-11-24 Havoc Pennington <hp@redhat.com> - - * Apply patch from Gregory Merchan to avoid using CurrentTime when - setting input focus. Bug #108881 - -2003-11-23 Havoc Pennington <hp@redhat.com> - - * src/compositor.c: move xcompmgr code in here (minus drop - shadows), untested since Keith's server just crashes at the - moment. "It compiles" - -2003-11-20 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_new_with_attrs): new function - - * src/display.c, src/screen.c: create the compositor and feed - windows and events to it - -2003-11-20 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_notify_focus): revert the change here - -2003-11-17 Rob Adams <readams@readams.net - - * src/window.c (set_allowed_actions_hint): increment i between - resize and fullscreen. - -2003-11-16 Rob Adams <readams@readams.net> - - Create COMPLIANCE document describing metacity specification - compliance. Right now gives detailed EWMH compliance; still need - to add ICCCM compliance information. Also some minor fixes to - bring metacity into compliance on some points. - - * COMPLIANCE: new file - - * src/display.h, src/display.c (meta_display_open), - src/screen.c (set_supported_hint): add - atom_net_wm_action_fullscreen and atom_net_wm_action_minimize - - * src/window.c (set_allowed_actions_hint): some fixes to which - hints to set and add fullscreen and minimize. - -2003-11-16 Rob Adams <readams@readams.net> - - * src/window.c (meta_window_notify_focus): add paranoia check to - make sure a window is really on a workspace before inserting it at - the beginning of the MRU list. Maybe there's a race condition - with focusing and workspace switching. Hopefully a fix for - #122016. - -2003-11-15 Havoc Pennington <hp@redhat.com> - - * src/main.c (main): fix warning - - * src/compositor.c: add a new file to contain compositing manager - functionality; not yet implemented at all. - -2003-11-15 Rob Adams <readams@readams.net> - - Inherit visual from frame window so that metacity will work with - the new compositing manager extension work by Keith on - freedesktop.org, so that ARGB windows can be full - alpha-transparent without a metacity frame getting drawn in the - background. In the long term, we need to actually set alpha - values when drawing the frame so that it will really work; this is - a stopgap solution. Patch from Keith Packard; see Bug 126875. - - * src/frame.c (meta_window_ensure_frame): pass client visual to - frame. - - * src/ui.[ch] (meta_ui_create_frame_window): add new xvisual - parameter and use it to create new window. - -2003-11-15 Rob Adams <readams@readams.net> - - * src/window.c (update_net_wm_type): don't set window->type_atom - here so that the type-inference code will actually be called. Fix - for #126873 from Keith Packard. - -2003-11-08 Rob Adams <readams@readams.net> - - * src/window.c (meta_window_move_resize_internal): configure frame - first if we grow more than we shrink combined in both dimensions. - Patch from Soren Sandmann for #108925. - -2003-11-07 Rob Adams <readams@readams.net> - - * src/place.c (meta_window_place): use maximize_after_placement to - automaximize in meta_window_place; avoids a problem with not - recalculating the frame geometry after auto-maximizing. - -2003-11-07 Rob Adams <readams@readams.net> - - * src/window.c (window_should_be_showing): show the window if it's - a transient of a dock or desktop, since otherwise such windows are - invisible in show desktop mode. Fix for #124648. - -2003-11-07 Rob Adams <readams@readams.net> - - * src/main.c (main): Try harder to find a theme in the event that - the theme in the preference cannot be found. Patch from Marcin - Krzyzanowski. See #125815. - - * src/place.c (meta_window_place): use "visual" centering for - dialog placement and clip new dialogs to an xinerama workspace. - Fix for #118336. - -2003-10-30 Havoc Pennington <hp@redhat.com> - - * src/menu.c (meta_window_menu_new): patch to avoid creating - stick/unstick menu items when only one workspace, bug #116563 - from Michael Terry - -2003-10-25 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_notify_focus): if a window is focused - which is not either a dock or a transient in the same group as a - dock, shuffle all dock/desktop windows to the end of the MRU list - so they won't annoyingly get focus all the time. #123816 - -2003-10-15 Yukihiro Nakai <nakai@gnome.gr.jp> - - Gettextize metacity-theme-viewer. #121747 - - * src/theme-viewer.c: gettextize. - * po/POTFILES.in: Add src/theme-viewer.c - -2003-10-13 Havoc Pennington <hp@redhat.com> - - In the "prefs cause code complexity" department, here's a "sloppy - focus die die die" kind of moment. - - * src/display.c (meta_display_grab_focus_window_button): don't - grab in sloppy focus mode, since we were dropping the grab on - window enter anyway this just removes races from the current - behavior. - - * src/display.c (prefs_changed_callback): ungrab/grab on focus - mode changes, since we treat sloppy and click differently. - -2003-10-12 Havoc Pennington <hp@redhat.com> - - Merge reduced_resources mode patch from the branch. Offers - wireframe and no-animations. - - * src/window.c (implement_showing): no animation if we are - in reduced resources mode - - * src/prefs.c: add REDUCED_RESOURCES pref - - * src/window.c (meta_window_update_keyboard_resize): fix to - modify grab_anchor_window_pos to grab_wireframe_rect if - appropriate instead of window->rect - - * src/display.h (struct _MetaDisplay): add grab_start_serial used - to avoid responding to events that occurred prior to the grab - initialization. - - Still broken in various ways, specifically EnterNotify that - occurred prior to XGrabPointer is processed as if it occurred - after. - - * src/window.c (meta_window_update_keyboard_move): add this - instead of meta_window_warp_pointer() crack - - * src/effects.c (meta_effects_update_wireframe): draw a kind of - grid for the wireframe, instead of just a rectangle, like twm - - * src/screen.c (meta_screen_new): line width of 3 for the XOR gc - - "Reduced resources" mode based on wireframe patch from - Erwann Chenede. Still pretty buggy. - - * src/keybindings.c (process_keyboard_move_grab) - (process_keyboard_resize_grab): add gruesome wireframe hacks - - * src/display.c (meta_display_end_grab_op): end wireframe - (meta_display_begin_grab_op): begin wireframe - - * src/effects.c (meta_effects_end_wireframe) - (meta_effects_update_wireframe, meta_effects_begin_wireframe): - routines to draw the wireframe stuff - - * src/window.c (window_should_be_showing): hide window when - doing wireframe, commented out as it breaks grab - * src/window.c (meta_window_refresh_resize_popup): handle wireframe - - * src/screen.c (meta_screen_new): create a screen->root_xor_gc - for use in drawing wireframes - - * src/frames.c (meta_frames_push_delay_exposes): repaint - everything before we delay - -2003-10-11 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_begin_grab_op): initialize - display->grab_have_pointer to FALSE, previously I think you could - get a case where we didn't have the grab and thought we did. - Bugs were reported with this happening. Of course we still have - the "why did the grab fail" problem, but it should be less - noticeable with this fixed. - -2003-10-06 Rob Adams <readams@readams.net> - - * src/constraints.c (constraint_onscreen_*_func): disable onscreen - resize constraints for right, left, and bottom, since there is no - way to violate onscreen constraints by resizing in these - directions and the code to implement the constraints made some - incorrect assumptions. Fix for #120701, #120756, #123165, - #123631, #123838. - -2003-10-06 Žygimantas Beručka <uid0@tuxfamily.org> - - * configure.in: Added "lt" to ALL_LINGUAS - -2003-10-01 Havoc Pennington <hp@redhat.com> - - * NEWS: update - - * configure.in: 2.6.2 - -2003-09-30 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_queue_move_resize): add the moveresize - idle at META_PRIORITY_RESIZE so it runs before GTK does any - drawing, may fix bug #109211 (seems to for me) - - * src/ui.h (META_PRIORITY_RESIZE): add this between GTK - resize/redraw priorities - - * src/display.c (meta_display_queue_retheme_all_windows): remove - some debug spew from meta_warning - -2003-09-30 Havoc Pennington <hp@redhat.com> - - * src/testasyncgetprop.c: remove nonstandard header include, - #121870 - -2003-09-30 Havoc Pennington <hp@redhat.com> - - * src/tools/metacity-message.c (main): call - bind_textdomain_codeset(), fix from Yukihiro Nakai bug #121743 - -2003-07-28 Rached Ben Mustapha <rached@benmur.net> - - Fix bug #118428 - - * src/window.c (redraw_icon): Also redraw window icon if the window - is not mapped but its frame is. - (idle_update_icon): Unset the window->update_icon_queued flag. - -2003-09-29 Havoc Pennington <hp@redhat.com> - - * src/tabpopup.c (meta_ui_tab_popup_new): put a random cap on - number of characters in the title of each window, bug #109301 - -2003-09-29 Havoc Pennington <hp@redhat.com> - - * configure.in: put -lXext in Xrandr check, bug #115996 - -2003-09-29 Havoc Pennington <hp@redhat.com> - - * src/wm-tester/test-size-hints.c: a little program to test size - hints, for now just a 0x0 min size to verify bug #113320 - -2003-09-29 Havoc Pennington <hp@redhat.com> - - * src/async-getprop.c (async_get_property_handler): attempt to fix - this to return the data as an array of long even on 64-bit as with - XGetWindowProperty() breakage, bug #114035, credit to Gwenole - Beauchesne for tracking down. - -2003-09-29 Havoc Pennington <hp@redhat.com> - - * src/xprops.c (cvtINT16toInt): fix the 64-bit check not to use - macros from the X tree that don't get set - - * configure.in: check for sizes of various types - -2003-09-29 Havoc Pennington <hp@redhat.com> - - * src/delete.c (meta_window_delete): don't move the focus after - you click the close button on a window. bug #108706 - -2003-09-29 Havoc Pennington <hp@redhat.com> - - * src/main.c (find_accessibility_module): fix warnings (one was a - real bug) - - * src/ui.c (meta_gdk_pixbuf_get_from_pixmap): fix warning that - probably explains remaining crash on bug #116923. Jeez, need to - use -Werror here or something. - - Fix #103575, spawn child processes on proper screen. - - * src/keybindings.c (error_on_command): pass --screen to - metacity-dialog - (handle_run_command): launch user command with DISPLAY reflecting - the screen you launch it from - - * src/delete.c (delete_ping_timeout_func): pass --screen to - metacity-dialog - -2003-09-26 Havoc Pennington <hp@redhat.com> - - * src/display.c (event_callback): when focus on root window - becomes None, set it to something other than None so keybindings - keep working and print a warning about how some application sucks. - #84564 - (event_callback): Fix debug spew to print focus event details - properly - (meta_display_open): when setting initial focus, always use - RevertToPointerRoot and fix the focus if it's None or PointerRoot - -2003-09-26 Padraig O'Briain <padraig.obriain@sun.com> - - * src/Makefile.am: Add -DMETACITY_LIBDIR to support loading of modules - * src/main.c: Add functions find_accessibility_module, - accessibility_invoke_module and accessibility_invoke - (main); Check whether GConf accessibility key is true and if so - load accessibility modules. This code is based on the libgnome code. - - src/tabpopup.c (meta_ui_tab_popup_new): Set accessible role of - accessible for label containing window name to STATUSBAR so - AT can be aware of window name. - - This fixes bug #120025 - -2003-09-24 Havoc Pennington <hp@pobox.com> - - * src/session.c (io_from_warning_dialog): fix hang when we get - EOF, #121376 from Laurent Vivier - -2003-09-22 Taneem Ahmed <taneem@bengalinux.org> - - * configure.in: Added "bn" to ALL_LINGUAS. - -2003-09-20 Åsmund Skjæveland <aasmunds@fys.uio.no> - - * configure.in: Added Norwegian (nynorsk) translation code to - ALL_LINGUAS - -2003-09-20 Rob Adams <readams@readams.net> - - Fix bug where multiple entries could appear in MRU lists, or no - entry when sticking/unsticking windows. Fix for #122016 - - * src/window.c (meta_window_stick): use window->screen->workspaces - instead of window->workspaces. - (meta_window_unstick): use window->screen->workspaces instead of - window->workspaces. - -2003-09-19 Rob Adams <readams@readams.net> - - Fix a bug with partial-width panel struts caused by incorrect - computation of rectangle widths, and another when using different - screen resolutions on xineramas. See #122404. Also fix a crash - bug with the MRU list when sticking and unsticking windows. See - #120809. - - * src/constraints.c (get_outermost_onscreen_positions): Fix - off-by-one error with partial-width struts. - - * src/window.c (meta_window_update_struts): Fix off-by-one error - with partial-width struts. - (meta_window_stick): assign back to GList after g_list_append - (meta_window_unstick): assign back to GList after g_list_append - - * src/workspace.c (ensure_work_areas_validated): For right and - bottom struts, compute strut relative to root window and not to - xinerama edge in compliance with EWMH recommendations. - - -2003-09-17 Fatih Demir <kabalak@gtranslator.org> - - * configure.in: Added "ta" (Tamil) to the languages' list. - -Wed Sep 10 15:38:09 2003 Jonathan Blandford <jrb@redhat.com> - - * configure.in: Rerelease 2.4.0.1 to fix glib-gettext problem. - -2003-09-08 Havoc Pennington <hp@redhat.com> - - * configure.in: remove "this is the unstable branch" warning - -2003-09-08 Havoc Pennington <hp@redhat.com> - - * configure.in: 2.6.0 - -2003-09-04 Havoc Pennington <hp@redhat.com> - - * configure.in: 2.5.5 - - * HACKING: add instructions on how to make a release - -2003-08-29 Rob Adams <robadams@ucla.edu> - - * src/ui.c (meta_gdk_pixbuf_get_from_pixmap): harden against null - return from gdk_pixmap_foreign_new. Fix for #116923. - -2003-08-26 Guntupalli Karunakar <karunakar@freedomink.org> - - * configure.in: Added "hi" (Hindi) to ALL_LINGUAS. - -2003-08-20 Rob Adams <robadams@ucla.edu> - - Complete the transition to using the MRU window as the default - focus window instead of the topmost window; fixes a number of - problems with sloppy focus and utility windows. See #112031. - - * src/window.c (meta_window_free): call - meta_workspace_focus_mru_window - (meta_window_minimize): call meta_workspace_focus_mru_window - -2003-08-20 Rob Adams <robadams@ucla.edu> - - * src/constraints.c (meta_window_constrain): do northwest resize - when maximizing and fullscreening to avoid potential "off-by-one" - problems. - -2003-08-19 Rob Adams <robadams@uclu.edu> - - * src/stack.c (get_standalone_layer): put windows with - wm_state_below at the bottom. Make this higher priority than full - screen layer; see #120238. - -2003-08-18 Rob Adams <robadams@ucla.edu> - - * src/constraints.c (meta_window_constrain): recalculate frame - geometry if the window gets maximized after placement, since it's - likely to change. Fix for #120117. - -2003-08-17 Ray Strode <halfline@hawaii.rr.com> - - * src/delete.c (meta_window_delete): Use MRU list to find focusing - window after a window is deleted instead of using top window. Fix - for #108643. - -2003-08-16 Havoc Pennington <hp@pobox.com> - - Patch from Soeren Sandmann #108926 to improve opaque resize - - * src/frame.c (meta_window_ensure_frame): new function - - * src/ui.c (meta_ui_create_frame_window): new function to create - a frame with GDK, so that GDK's invalidation etc. work properly - -2003-08-16 Havoc Pennington <hp@pobox.com> - - * src/display.c (xcursor_for_op): fix cursor for - META_GRAB_OP_MOVING, #111943 from John Paul Wallington - -2003-08-15 Rob Adams <robadams@ucla.edu> - - * src/constraints.c (meta_window_constrain): move to upper left - corner since we're resizing/moving instead of moving/resizing. - Fix for #119988. - -2003-08-15 Ray Strode <halfline@hawaii.rr.com> - - Changed MRU list to be per workspace instead of per display, so - sticky windows don't hijack the window focus after workspace - switching (Bug #97635). - - * src/delete.c (meta_window_delete): Use - meta_workspace_focus_top_window instead of - meta_screen_focus_top_window. - - * src/display.c (meta_display_open): Stop using display->mru_list. - (find_tab_forward): - (find_tab_backward): - (meta_display_get_tab_list): Use workspace->mru_list instead of - display->mru_list and remove unneeded calls to - meta_window_visible_on_workspace - - * src/display.h: Remove mru_list from MetaDisplay - - * src/keybindings.c (handle_toggle_desktop): Use - meta_workspace_focus_top_window instead of - meta_screen_focus_top_window. - - * src/screen.c (meta_screen_focus_top_window): - (meta_screen_focus_default_window): Remove functions. - (meta_screen_show_desktop): Use meta_workspace_focus_top_window - instead of meta_screen_focus_top_window. - - * src/screen.h: Remove meta_screen_focus_top_window and - meta_screen_focus_default_window declarations. - - * src/window.c (meta_window_new): Stop using display->mru_list. - (meta_window_free): Use meta_workspace_focus_top_window - instead of meta_screen_focus_top_window and stop using - display->mru_list. - (meta_window_stick): Add sticky window to all workspace MRU lists. - (meta_window_unstick): Remove non-sticky window from the workspace - MRU lists it doesn't belong in. - (meta_window_notify_focus): Move newly focused window to the front - of active workspace's MRU list. - - * src/workspace.c (meta_workspace_new): Initialize - workspace->mru_list to NULL. - (meta_workspace_add_window): Add window to workspace's MRU list. - (meta_workspace_remove_window): Remove window from workspace's MRU - list. - (meta_workspace_activate_with_focus): Use - meta_workspace_focus_default_window instead of - meta_screen_focus_default_window. - (meta_workspace_focus_default_window): - (meta_workspace_focus_mru_window): - (meta_workspace_focus_top_window): Add functions. - - * src/workspace.h: Add mru_list to MetaWorkspace and add function - declarations for meta_workspace_focus_default_window, - meta_workspace_focus_mru_window, meta_workspace_focus_top_window. - -2003-08-14 Rob Adams <robadams@ucla.edu> - - Allow windows that are too tall for the workarea to break the - onscreen constraints just enough so that their bottom edges can be - made visible. Fix for #106740. Also, changes constraints to - constrain the resize and then the move to avoid complexities in - the code for the above fix. - - * src/constraints.c (get_outermost_onscreen_positions) - Compute the "effective" height of the work area and the minimum - size for the window to compute a value by which a window is - allowed to violate the top constraint. - (meta_window_constrain): convert to a resize then a move instead - of a move then resize. - -2003-08-13 Rob Adams <robadams@ucla.edu> - - * configure.in: remove metacity.spec from AC_OUTPUT - -2003-08-13 Havoc Pennington <hp@redhat.com> - - * metacity.spec.in: remove, nobody is maintaining it. - -2003-08-13 Laurent Dhima <laurenti@alblinux.net> - - * configure.in: Added "sq" to ALL_LINGUAS. - -2003-08-10 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_new): don't select for button - press/release events, as that keeps other clients from doing so, - and it doesn't seem that metacity has any reason to do it. - Patch from Andreas Volz. - -2003-08-08 Bastien Nocera <hadess@hadess.net> - - * src/metacity-dialog.c: (kill_window_question), - (warn_about_no_sm_support): fix markup being ignored when a window - title has a forbidden character in it (eg. "Send & Receive") - * src/tools/metacity-window-demo.c: fix warning - -2003-07-29 Arvind Samptur <arvind.samptur@wipro.com> - - * src/xprops.c (utf8_list_from_results): Number of - strings we are processing is one more than required. - - Also get the string count right even without a null byte at the end. - Pointed out by Havoc. - -2003-07-27 Rob Adams <robadams@ucla.edu> - - * src/window.c (update_move): Update window shaking loose so that - the window is moved to the pointer and certain drag state is - properly restored once windows "reattach". Fix for #115000 based - on the patch by Jurg Billeter. - - * src/screen.c (meta_screen_resize): Invalidate work areas after - an xrandr screen size update. Fix for #117230. - - * src/stack.c (window_is_fullscreen_size): Check the bottom corner - of the window in addition to the top corner. Fix for #118194. - - * src/constraints.c (meta_window_constrain): Support aspect ratio - hints in the new constraints code. Fix for #113798. - - * src/tools/metacity-window-demo.c (toggle_aspect_ratio): toggle - the aspect ratio hints to force a 16:9 aspect ratio. - (do_appwindow): add a button to toggle aspect ratio. - -2003-07-27 Havoc Pennington <hp@pobox.com> - - * src/theme-viewer.c (run_theme_benchmark): also measure wall - clock time, and run over a number of window sizes. - -2003-07-15 Havoc Pennington <hp@redhat.com> - - * NEWS: update - - * configure.in: 2.5.3 - -2003-07-12 Pablo Saratxaga <pablo@mandrakesoft.com> - - * configure.in: Added Walloon (wa) to ALL_LINGUAS - -2003-07-04 Havoc Pennington <hp@pobox.com> - - * Makefile.am (EXTRA_DIST): add rationales.txt - -2003-07-02 Jordi Mallach <jordi@sindominio.net> - - * src/metacity.desktop.in: Add X-GNOME-Bugzilla entries. - -2003-07-01 Padraig O'Briain <padraig.obriain@sun.com> - - * src/keybindings.c (process_tab_grab): Activate window before ending - grab. This fixes bug #114037. - -2003-06-20 Rob Adams <robadams@ucla.edu> - - * src/window.c (meta_window_unmaximize): Update grab state when we - unmaximize so double-clicking doesn't cause weird window-jumping - problems. See #116292. - -2003-06-29 Rob Adams <robadams@ucla.edu> - - * src/constraints.c (meta_window_constrain): Actually maximize - after placement. See #116285. - -2003-06-26 Havoc Pennington <hp@pobox.com> - - * src/workspace.c (meta_workspace_invalidate_work_area): nuke the - lists of struts here, to improve confidence that we never try to - use them after a window with rects in the list gets freed. - (it wasn't broken before I don't think, just making the - code more robust against future mods) - - * src/window.c (meta_window_update_struts): replace magic "75" - with a macro - - * src/constraints.c (constraint_hints_applies_func): don't apply - hints to maximized or fullscreen, rather than only fullscreen - (constrain_move): add paranoia max number of iterations to the - heuristic loop - -2003-06-26 Rob Adams <robadams@ucla.edu> - - Add keybinding to allow the user to toggle _NET_WM_STATE_ABOVE on - windows. Disabled by default. See #98387. - - * src/keybindings.c (handle_toggle_above): new function implements - the keybinding - - * src/metacity.schemas.in: add toggle_above keybinding - - * src/prefs.[ch]: add toggle_above keybinding - - * src/window.[ch] (meta_window_make_above): new function to put a - window into the above state - (meta_window_unmake_above): new function takes a window out of the - above state - -2003-06-26 Mohammad DAMT <mdamt@bisnisweb.com> - - * po/id.po: Added Indonesian translation - * configure.in: Added "id" to ALL_LINGUAS - -2003-06-25 Rob Adams <robadams@ucla.edu> - - Update constraints code to support the new _NET_WM_STRUT_PARTIAL - EWMH draft specification. See #86682. Also, fix a bug involving - work area invalidation on metacity startup. Fix for #108497. - Finally, some minor fixes for full screen windows. - - * src/window.h: Add new MetaStruts structure to store strut rects - for a window. Remove has_struts and do_not_cover flag, and - support new MetaStruts instead of the four ints. - - * src/window.c (meta_window_new): change initialization to work - with new struts. Also, move meta_window_update_struts call to - after the workspaces are initialized to fix #108497. Remove - do_not_cover and related code. - (process_property_notify): add strut_partial - (update_struts): change function name to meta_window_update_struts - and expose in external MetaWindow API. Support partial width - struts and the new strut rects. - - * src/workspace.h: add new GSLists containing pointers to all - relevant struts for this workspace. - - * src/workspace.c (meta_workspace_new): initialize the list of - strut rects for this workspace. - (meta_workspace_free): free the strut rect lists - (ensure_work_areas_validated): support new struts and new strut - rect lists. Unleash the per-xinerama work areas. - - * src/constraints.c (get_outermost_onscreen_positions): Use the - current window position along with the new per-workspace strut - rects to compute the constraints that apply to a particular - window. - (constraint_hint_applies_func): don't do hints constraints on - fullscreen windows - (update_position_limits): for maximized windows use the work areas - to set the position limits; for other windows rely on the struts - constraints to be computed later in - get_outermost_onscreen_positions - (meta_window_constrain): don't apply aspect ratio hints to full - screen windows - - * src/display.c (meta_display_open): add _NET_WM_STRUT_PARTIAL atom - (meta_rectangle_equal): new helper function for MetaRectangles - (event_queue_callback): #ifndef out if USE_GDK_DISPLAY not set to - avoid compiler warning - - * src/display.h: add atom_net_wm_strut_partial, and add - meta_rectangle_equal. - - * src/screen.c (meta_screen_rect_intersects_xinerama): change - _window_intersects_ to _rect_intersects_ which is more useful now. - (meta_screen_resize_func): update struts on windows with struts - since struts are relative to the screen size, and this function is - called when the screen size updates. - - * src/screen.h (meta_screen_rect_intersects_xinerama): change - _window_intersects_ to _rect_intersects_ which is more useful now. - - * src/window-props.c (meta_display_init_window_prop_hooks): add - hook for strut_partial - - * src/tools/metacity-window-demo.c: Support partial-width struts - on the dock window tests for metacity testing purposes. - -2003-06-22 Samúel Jón Gunnarsson <sammi@techattack.nu> - - * configure.in: Added "is" to ALL_LINGUAS - -2003-06-12 Rob Adams <robadams@ucla.edu> - - * src/display.c (event_callback): Focus on mouse click in - sloppy/mouse to fix keynav. Fix for #115072. - -2003-06-12 Rob Adams <robadams@ucla.edu> - - * src/Makefile.am: honor --disable-schemas-install. Fix for - #106123 from Julio Merino - -2003-06-12 Rob Adams <robadams@ucla.edu> - - Remove legacy support for Gnome 1 hints, since we deem it unlikely - that anyone is running a current metacity with Gnome 1. The - removed hints are _WIN_WORKSPACE, _WIN_LAYER, _WIN_PROTOCOLS, - _WIN_SUPPORTING_WM_CHECK, and _WIN_HINTS. Thanks to Ben Jansens - for much of this patch. - - * display.c (meta_display_open): remove hints - - * display.h: remove atoms for hints - - * screen.c (set_wm_check_hint): don't set legacy hint - (set_supported_hint): don't set legacy hint - - * window-props.c (init_win_workspace): removed - (reload_win_workspace): removed - (meta_display_init_window_prop_hooks): remove hints - - * window.h: remove do_not_cover flag - - * window.c: remove GnomeWinHints enum - (recalc_do_not_cover_struts): removed - (meta_window_new): don't initialize removed flags or compute - legacy struts - (move_resize_cmp): removed - (idle_move_resize): Don't bother sorting the idle queue - (meta_window_client_message): don't set legacy hint - (process_property_notify): remove hints - (update_net_wm_type): don't fall back to WIN_LAYER hint - (update_struts): remove legacy struts - -2003-06-12 Havoc Pennington <hp@pobox.com> - - * src/display.c (event_callback): make raise-on-click explicitly - only happen in click to focus mode. - - * src/window.c (update_move): apply patch from Jurg Billeter to - allow you to "shake loose" maximized windows and move them between - Xinerama heads. #93586 - - * src/display.c: delete event_queue_callback - - * src/display.h (struct _MetaDisplay): get rid of - grab_current_window_pos and grab_current_root_[xy] as I could find - absolutely no code using them for anything. They were just sort of - randomly assigned to for no apparent reason. - - * src/display.c (event_callback): double-click timeout is per - screen, so get the screen and pass screen->ui to - meta_ui_get_double_click_timeout() - - * src/ui.c (meta_ui_get_double_click_timeout): take a MetaUI - argument so we get the right settings for each screen - (meta_ui_get_drag_threshold): new function - -2003-06-09 Rob Adams <robadams@ucla.edu> - - Revamp placement policy for windows that are maximized when they - are mapped, including windows that set a hint to be maximized or - windows that are auto-maximized using our heuristic. See #111902. - - * src/window.h: add new flag maximize_after_placement and new - function meta_window_maximize_internal. - - * src/window.c (meta_window_new): initialize - maximize_after_placement to FALSE and remove the automaximize - heuristic. - (meta_window_maximize_internal): new function accepts a saved_rect - argument to be used as the new saved_rect for the window, and does - not queue a move_resize. - (meta_window_maximize): re-implement using - meta_window_maximize_internal. - (update_net_wm_state): If a window has a maximize hint set on - startup set maximize_after_placement to TRUE - - * src/constraints.c (meta_window_constrain): Update the xinerama - information in the ConstraintInfo after placing the window, and - maximize the window after placement if - window->maximize_after_placement - - * src/place.c (find_first_fit): take a natural xinerama list as an - argument instead of generating it here - (constrain_placement): remove function, since it is no longer - needed - (meta_window_place): generate the natural xinerama list here and - pass it into find_first_fit. If find_first_fit fails, use the - list to find empty xineramas where we can place windows that may - be maximized later. This makes maximized windows follow the - correct placement policy. Move the automaximize heuristic here. - -2003-06-09 Rob Adams <robadams@ucla.edu> - - * src/metacity-dialog.c (warn_about_no_sm_support): install an - alarm to timeout the no-sm-dialog after 4 minutes of inactivity. - Patch from Ximian. See #114789. - -2003-06-07 Rob Adams <robadams@ucla.edu> - - * src/window.c (meta_window_new): call meta_group_compute_group - after setting window->desc to avoid SIGSEGV when verbose mode is - enabled. - -2003-06-07 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_notify_focus): drop the mouse button - grabs for the focused window; we'll see if this breaks anything. - It should fix #102209 - -Fri Jun 6 19:27:53 2003 Jonathan Blandford <jrb@gnome.org> - - * src/metacity.schemas.in: fix the location of the schemas file. - -2003-06-04 Rob Adams <robadams@ucla.edu> - - * src/window.c (meta_window_new): don't be stupid and set - window->group = NULL after calling meta_window_compute_group. - - * src/group.c (meta_window_get_group): assert that window->group - != NULL in here instead of computing the group to ensure - robustness. - -2003-06-04 Rob Adams <robadams@ucla.edu> - - Precompute groups to guarantee that meta_group_list_windows always - returns the correct list of windows. See Bug #96973 - - * src/window.h: change cached_group variable to group - - * src/window.c (meta_window_new): change cached_group to group and - call meta_window_compute_group - - * src/groups.c (meta_window_get_group): simply return - window->group rather than computing it and returning - window->cached_group - (meta_window_compute_group): new function computes window->group. - Designed to be called once from meta_window_new - (remove_window_from_group): change cached_group to group - (meta_window_group_leader_changed): call meta_window_compute_group - instead of meta_window_get_group - -2003-05-29 Rob Adams <robadams@ucla.edu> - - Use a new property _METACITY_SENTINEL to eliminate a race - condition that causes focus to behave badly with sloppy/mouse - focus when lots of windows are mapped/unmapped, such as with a - workspace switch. The EnterNotify events on a display are ignored - until the PropertyNotify sent after all the window maps is - received. This is a fix for #110970. - - * src/display.[ch]: New _METACITY_SENTINEL atom. - (event_callback): ignore EnterNotify if the sentinel isn't clear, - and decrement the sentinel counter when the PropertyNotify is - received. - (meta_display_increment_focus_sentinel): new function. Increments - the sentinel counter and updates the property on a root window on - this display. - (meta_display_decrement_focus_sentinel): Decrement the sentinel - counter. - (meta_display_focus_sentinel_clear): returns whether the sentinel - counter is zero. - - * src/window.c (idle_calc_showing): after showing windows, call - meta_display_increment_focus_sentinel on each display for windows - to be shown. - - * src/workspace.[ch] (meta_workspace_activate_with_focus): new - function activates a workspace and focuses a particular window - after the workspace is activated. - (meta_workspace_activate): now just a wrapper for - meta_workspace_activate_with_focus - - * src/keybindings.c: use new meta_workspace_activate_with_focus - function to ensure that focus will follow the focused window - through the workspace switch. - -2003-05-29 Havoc Pennington <hp@redhat.com> - - * src/theme-parser.c (meta_theme_load): s/int/gsize/ for - g_file_get_contents() (found independently by - marcus@freebsd.org on SPARC and James Laska on s390x; - #113661 - - * src/main.c (main): fix theme location mentioned in error message - -2003-05-29 Ray Strode <halfline@hawaii.rr.com> - - Get and use double-click speed from GtkSettings (Bug #103218). - - * src/ui.c, src/ui.h: - add function meta_ui_get_double_click_timeout for looking up - the global double-click speed. - - * src/display.c, src/display.h: remove double_click_time - field from MetaDisplay and use meta_ui_get_double_click_timeout - instead. - -2003-05-29 Rob Adams <robadams@ucla.edu> - - * src/main.c (main): chdir to the user's home directory on - startup. See #113755. - - * src/stack.c (get_standalone_layer): a window should be in the - fullscreen layer if it or any of its transient descendants are - focused or expecting the focus and it is either fullscreen or - fullscreen sized. Fix for #104369. - - * src/stack.c (is_focused_foreach): foreach used by - get_standalone_layer to find focused transient descendants. - -2003-05-20 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (meta_change_keygrab): the mask - display->ignored_modifier_mask wasn't being bound, - due to "<" instead of "<=" (most people didn't notice - as display->ignored_modifier_mask included Scroll_Lock). - Red Hat bugzilla #91301 reported by Youssef Makki - - * src/display.c (meta_change_button_grab): make corresponding - change for button grabs. - -2003-05-20 Havoc Pennington <hp@redhat.com> - - * NEWS: update - - * configure.in: 2.5.2 - -2003-05-20 Anders Carlsson <andersc@codefactory.se> - - * src/metacity-dialog.c: (kill_window_question): - Split up the strings to make life easier for translators. - -2003-05-20 Anders Carlsson <andersca@codefactory.se> - - * src/metacity-dialog.c: (kill_window_question): - Fix the wording and HIGify the dialog. - -2003-05-18 Havoc Pennington <hp@pobox.com> - - * src/window.c (unminimize_window_and_all_transient_parents): - revert broken change that assumed foreach_ancestor iterated - over the window itself. Andrew Sobala, Rob Adams, - #113232 - -2003-05-16 Rob Adams <robadams@ucla.edu> - - Flip the workspace when using up/down/left/right for move window - to, but not when specifying a workspace explicitly as in move to - workspace 4. Possible fix for #105492. - - * src/keybindings.c (do_handle_move_to_workspace): new function - moves a window to a workspace with the option to flip to that - workspace. - (handle_move_to_workspace): Use new do_handle_move_to_workspace - function without flipping (a keybinding) - (handle_move_to_workspace_flip): Use new - do_handle_move_to_workspace function with flipping (a keybinding) - -2003-05-16 Havoc Pennington <hp@redhat.com> - - * src/frames.c (meta_frames_paint_to_drawable): fix for - bug #104018 from David Santiago, change button state to - normal while it's being pressed if you move the mouse - outside it. Do this by tracking prelit_control for whether - to draw a button as active, not just for whether to draw - it as prelit. - (meta_frames_motion_notify_event): also update prelit_control - while clicking a button - -2003-05-16 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_new): fill in window->desc sooner - since we use it sooner now. - - * src/display.c (meta_display_open): init - display->grab_update_alarm - - * src/window.c (meta_window_new): initialize the always_sticky - field - (meta_window_new): initialize the update_icon_queued field - - Patch from Julien Olivier bug #92335 for converting "show desktop - mode" to "all windows are minimized" when you open a new window, - instead of just mapping all the windows again. - - * src/window.c (meta_window_activate): minimize all windows before - coming out of show desktop mode. - (meta_window_unminimize): don't toggle show desktop mode here - - * src/screen.c (meta_screen_minimize_all_except): new function - -2003-05-01 Havoc Pennington <hp@redhat.com> - - * src/theme-parser.c (meta_theme_load): fix memleak on error - -2003-05-16 Telsa Gwynne <hobbit@aloss.ukuu.org.uk> - - * configure.in: Added "cy" (Welsh) to ALL_LINGUAS. - -2003-05-06 Danilo Ã
egan <dsegan@gmx.net> - - * configure.in: Added "sr" and "sr@Latn" to ALL_LINGUAS. - -2003-05-03 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (handle_move_to_workspace): when moving - window to another workspace, don't switch to that workspace. - - * src/window.c (menu_callback): when moving window to another - workspace, don't switch to that workspace. - -2003-05-03 Havoc Pennington <hp@pobox.com> - - * configure.in: 2.5.1 - - * NEWS: update - -2003-05-01 Rob Adams <robadams@ucla.edu> - - * src/constraints.c (constraint_onscreen_applies_func): Don't - apply onscreen constraints to full screen windows. Fix for - #110048 - -2003-04-29 Havoc Pennington <hp@redhat.com> - - * src/bell.h: include Xlib.h before XKBlib.h which is required on - Solaris. #111877 from Peter O'Shea - -2003-04-23 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (process_keyboard_move_grab): support - diagonal keypad keybindings, from Dafydd Harries - -2003-04-21 Havoc Pennington <hp@redhat.com> - - * purge HAVE_GTK_MULTIHEAD from the source code, not just from - configure.in. Yes I am a loser. - -2003-04-19 Masahiro Sakai <sakai@tom.sfc.keio.ac.jp> - - * configure.in: call AC_LIBTOOL_WIN32_DLL. - - * src/Makefile.am: add -no-undefined to libmetacity_private_la_LDFLAGS - and write dependency libraries in libmetacity_private_la_LIBADD. - -2003-04-06 Rob Adams <robadams@ucla.edu> - - * src/place.c (find_next_cascade): cascade on xinerama with - pointer instead of on first xinerama. - -2003-04-05 Rob Adams <robadams@ucla.edu> - - Update placement policy for screen with multiple xineramas. - Windows will be placed preferentially on the xinerama with the - pointer, and progressively further away as needed to find a place - where the window does not overlap other windows. - - * src/place.c (rect_fits_in_work_area): function - fit_rect_in_xinerama greatly simplified to work with new placement - policy. - (find_first_fit): implement new first fit placement scheme - - * src/screen.c (meta_screen_get_xinerama_neighbor): look for an - xinerama in the xinerama list that is adjacent to the specified - xinerama. - (meta_screen_get_natural_xinerama_list): return a list of - xineramas in the order to be preferred by the placement algorithm - as determined by the current location of the pointer. - - * src/screen.h: add function prototypes and an enum used by - meta_screen_get_xinerama_neighbor. - -2003-04-05 Rob Adams <robadams@ucla.edu> - - * src/place.c (center_tile_rect_in_area): Fix a minor off-by-one - error. See #110079. - -2003-03-30 Rob Adams <robadams@ucla.edu> - - * src/window.c (meta_window_move_resize_internal): When passing - frame geometry to meta_window_constrain, send null if no frame. - Possible fix for #109039. - -2003-03-29 Havoc Pennington <hp@pobox.com> - - * src/wm-tester/test-gravity.c (main): add --noframes option for - testing, showing how broken we currently are. - -Fri Mar 28 14:13:37 2003 Soeren Sandmann <sandmann@daimi.au.dk> - - * src/window.c (update_resize): Only cap refresh rate when not - using SYNC. Remove bogus update-if-we-moved-more-than-a-delta. - - * src/window.c (update_move): Don't cap refresh rate during - moves. Remove bogus update-if-we-moved-more-than-a-delta. - -2003-03-26 Havoc Pennington <hp@pobox.com> - - * NEWS: update - - * configure.in: release 2.5.0 - -Sun Mar 23 23:04:06 2003 Soeren Sandmann <sandmann@daimi.au.dk> - - * src/display.c (meta_spew_event): just return if we are not - verbose. - -2003-03-11 Havoc Pennington <hp@pobox.com> - - Should fix #108108, #106217, tracked down by Owen Taylor and - Frederic Crozat - - * src/window.c (meta_window_foreach_transient): change - MetaWindowForeachFunc to return a boolean for whether to continue - (meta_window_foreach_ancestor): new function - (window_should_be_showing): use meta_window_foreach_ancestor - (unminimize_window_and_all_transient_parents): ditto - (update_sm_hints): ditto - (meta_window_is_ancestor_of_transient): ditto - - * src/stack.c (get_maximum_layer_of_ancestor): use - meta_window_foreach_ancestor - -2003-03-16 Rob Adams <robadams@ucla.edu> - - * window.c (meta_window_show_menu): Free old window menu if it - already exists so we don't end up with more than one. Fix for - #108392. - -2003-03-14 Rob Adams <robadams@ucla.edu> - - * contraints.c (get_outermost_screen_positions): Don't try to - force a window onscreen by more than its width. Fix for #94815. - -2003-03-13 Rob Adams <robadams@ucla.edu> - - Make it so that the alt-tabbing won't try to go to a minimized - window by default. Fix for #107071. - - * display.c (meta_display_get_tab_list): use a GList instead of a - GSList - (meta_display_get_tab_next): use meta_display_get_tab_list to - decide what the next/previous tab window should be. - - * display.h (meta_display_get_tab_list): update function prototype - to return GList instead of GSList. - - * screen.c (meta_screen_ensure_tab_popup): update function to deal - with GList returned by meta_display_get_tab_list instead of GSList. - -2003-03-13 Christian Rose <menthos@menthos.com> - - * configure.in: Added "ml" to ALL_LINGUAS. - -2003-03-11 Paul Duffy <dubhthach@zion.nuigalway.ie> - - * configure.in: Added "ga" to ALL_LINGUAS - -2003-03-11 Rob Adams <robadams@ucla.edu> - - * src/constraints.c (meta_window_constrain): include left frame - geometry when maximizing or fullscreening windows. Fix for - #108127. - -2003-03-10 Roozbeh Pournader <roozbeh@sharif.edu> - - * configure.in: Added "fa" to ALL_LINGUAS. - -2003-02-27 Havoc Pennington <hp@redhat.com> - - Switch over to new constraints code, unquestionably introduces - some bugs, but should get us on the right path. - - * src/window.c (meta_window_get_work_area_all_xineramas): create - this function again as it turned out to be legitimate for window - position constraint - (adjust_for_gravity): use the width/height from the configure - request to compute the requested move - (meta_window_move_resize_internal): use meta_window_constrain - (update_size_hints): clamp max size to MAXSHORT to avoid worrying - about overflow stuff - - * src/constraints.c (meta_window_constrain): don't base placement - on uninitialized variables, general hacking - - * src/Makefile.am (metacity_SOURCES): add constraints.c, - constraints.h - - * src/constraints.c (meta_window_constrain): update the - cut-and-paste aspect ratio code to have latest bugfixes - -2003-03-08 Rob Adams <robadams@ucla.edu> - - * src/window-props.c (reload_normal_hints): Check that window min - and max size hints are at least 1. Fix for #107110. - -2003-02-27 Havoc Pennington <hp@pobox.com> - - Changes made on plane from FOSDEM, syncing from laptop. - - * src/main.c (main): add more debug spew about conditional - build stuff - (main): panic to "Simple" theme - - * src/window.c, src/window-props.c: move WM_NORMAL_HINTS and - WM_PROTOCOLS to new property system; don't queue move resize on - updating WM_PROTOCOLS; move WM_HINTS to new property system; - reload icon in an idle handler. - -2003-02-28 Mark McLoughlin <mark@skynet.ie> - - Give me back my keys. - - * src/keybindings.c: (meta_window_grab_keys): don't - grab keys on DOCK windows. - - * src/window.c: (recalc_window_type): re-grab the - keys. - -2003-02-26 Dmitry G. Mastrukov <dmitry@taurussoft.org> - - * configure.in: Added Belarusian to ALL_LINGUAS. - -2003-02-26 Mark McLoughlin <mark@skynet.ie> - - * src/keybindings.c: (handle_panel_keybinding): release - the keyboard grab before sending the action message to - the panel. - -2003-02-24 Mark McLoughlin <mark@skynet.ie> - - Take control of the panel's global keybindings. The - screenshot utility is hooked up using a special case - run_command and the menu and run dialog bindings are - done using the _GNOME_PANEL_ACTION ClientMessage - protocol. - - * src/display.[ch]: (meta_display_open): add some atoms. - - * src/keybindings.c: - (handle_panel_keybinding): impl to handle a keybinding - by sending an action message to the panel. - - * src/metacity.schemas.in: add schemas for the panel and - screenshot keybindings and the screenshot commands. - - * src/prefs.[ch]: (update_command), - (meta_prefs_get_gconf_key_for_command): impl special case - handling for the screenshot commands. They are stored at - the the end of the commands array but have named keys. - -2003-02-23 Havoc Pennington <hp@pobox.com> - - Patch from Rob Adams addresses #95014 (placement issues), - makes first fit algorithm "center tile", adds most code - for per-xinerama workspaces (#86682) but disables it for now. - - * src/workspace.c (meta_workspace_get_work_area_for_xinerama) - (meta_workspace_get_work_area_all_xineramas): new xinerama - functions, maintain workspace->work_areas with a different - work area for each xinerama. However for now all the work - areas are the same, because haven't quite figured out how - _NET_WM_STRUT is supposed to work - - * src/window.c: adapt to new meta_window_* xinerama APIs - (meta_window_get_work_area_current_xinerama): new xinerama - API - (meta_window_get_work_area_for_xinerama): new xinerama API - (constrain_position): be a bit more clever about which xinerama's - work area we choose to use. - - * src/stack.c: adapt to new Xinerama API - - * src/screen.c (reload_xinerama_infos): invalidate all work areas - (meta_screen_get_xinerama_for_rect): new function - (meta_screen_window_intersects_xinerama): new function - - * src/place.c (find_first_fit): change to use - "center tiling" (center a screen full of tiled windows, - rather than aligning them top left). Adapt to new - xinerama functions. - -2003-02-22 Rob Adams <robadams@ucla.edu> - - * src/metacity.schemas.in: change toggle_maximized to - toggle_maximize and toggle_shaded to toggle_shade in - action_double_click_titlebar long description to match the values - used by metacity - - * po/*.po: change toggle_maximized to toggle_maximize and - toggle_shaded to toggle_shade in action_double_click_titlebar long - description to match the values used by metacity - -2003-02-22 Rob Adams <robadams@ucla.edu> - - * window.c (set_wm_state): modify comment to explain why the icon - window element is set to None. Fix for #97357 thanks to Gregory - Merchan. - -2003-02-22 Havoc Pennington <hp@pobox.com> - - * README: fix a typo, pointed out by Steve Kemp - -2003-02-22 Havoc Pennington <hp@pobox.com> - - * src/prefs.c (MAX_REASONABLE_WORKSPACES): change max workspaces - to 36 #81855 - -2003-02-22 Havoc Pennington <hp@pobox.com> - - * src/display.c (event_callback): fix to unfocus window only when - you leave the window frame, not when you leave the window itself, - unless window has no frame. #100248 fix from Orien Vandenbergh - -2003-02-22 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_get_tab_next): when tabbing - backward, we are still tabbing *from* the most recently used - window, not from the least recently used window. - - * src/keybindings.c (struct _MetaKeyBinding): make keycode - unsigned to match XEvent - - Patch for #84999 based on patch from Mark McLoughlin - - * src/prefs.c: add an add_shift field to MetaKeyPref to - add shift when grabbing the given keybinding. - - * src/keybindings.c (rebuild_screen_binding_table) - (rebuild_window_binding_table): refactor to share code, - and honor add_shift field in MetaKeyPref - -2003-02-20 Havoc Pennington <hp@redhat.com> - - * src/stack.c (create_constraints): don't create constraints - between windows on different screens, #106086 tracked down - by Arvind - -2003-02-14 Arvind Samptur <arvind.samptur@wipro.com> - - * src/screen.c: (meta_screen_new) : Update the workspace - names from gconf and set the NET_DESKTOP_NAMES atom. - Renamed update_workspace_names() to set_workspace_names(). - Fixes #105498 - -2003-02-13 Havoc Pennington <hp@redhat.com> - - * configure.in: require GTK+ 2.2.0 - - * src/ui.c (meta_ui_init): remove hackaround for Pango X core - fonts backend - -2003-02-05 Abel Cheung <maddog@linux.org.hk> - - * configure.in: Added "en_GB" and "nl" to ALL_LINGUAS. - -2003-02-05 Akira TAGOH <tagoh@gnome.gr.jp> - - * src/main.c (usage): fix a typo and missing option. (#105186) - -2003-02-04 Havoc Pennington <hp@redhat.com> - - * src/themes/Simple/ChangeLog: nuke subdir ChangeLog, - there can be only one true ChangeLog. - -2003-01-30 Havoc Pennington <hp@redhat.com> - - * src/keybindings.c (process_event): match handlers to key events - using key codes, not key syms - -Thu Jan 30 22:55:16 2003 Jonathan Blandford <jrb@redhat.com> - - * src/themes/Makefile.am (THEMES): add Simple to the list of - themes. - - * src/metacity.schemas.in: change default theme to Simple. - -2003-01-29 Havoc Pennington <hp@pobox.com> - - * src/menu.c (meta_window_menu_new): don't create workspaces - menu items if only 1 workspace. Fix for #101952 from - Orien Vandenbergh - -2003-01-28 Bill Haneman <bill.haneman@sun.com> - - * Re-instated visual-bell patch - (please see ChangeLog entry for 2002-12-16 for details). - - * src/prefs.c: - (visual_bell_type_from_string): - Accept a NULL string for 'visual-bell-type'. - -2003-01-25 Havoc Pennington <hp@pobox.com> - - * src/stack.c (window_is_fullscreen_size): When checking if a - window is fullscreen size, only require it to be at the origin - of the work area, not at the origin of the screen/xinerama. - Still require it to be full screen in width x height. - May fix xine in the case where the user has a top panel. - - * src/window.c (constrain_position): restore the ability for - undecorated windows to position themselves overlapping the top - panel, but don't let decorated windows do so. Oh the hacks... - -2003-01-08 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_apply_startup_properties): small code - snippet to fix startup sequences that set legacy class/name - -2003-01-22 Havoc Pennington <hp@redhat.com> - - * src/async-getprop.c (async_get_property_handler): do not read - sizeof(long) off the X connection. The X protocol does not vary - by architecture. Fixes longstanding hang on all 64-bit platforms. - -2003-01-22 Havoc Pennington <hp@redhat.com> - - * src/tools/Makefile.am: fix conditional so we get - metacity-properties.c in the distribution #103071 - -2003-01-22 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_struts): be robust against the panel's - lame "set a negative number for struts" thing, even though - we'll also fix the panel. - -2003-01-21 Havoc Pennington <hp@pobox.com> - - Fix for the "mangles focus window when switching workspaces - and using mouse focus" bug - - * src/stack.c (meta_stack_get_default_focus_window_at_point): new - function - - * src/screen.c (meta_screen_focus_mouse_window): new function - (meta_screen_focus_default_window): new function - - * src/workspace.c (meta_workspace_activate): use the - new meta_screen_focus_default_window() - -2003-01-17 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_handle_mouse_grab_op_event): fix event - compression code to use GDK algorithm suggested by Owen, should be - more efficient. - -2003-01-22 Christian Rose <menthos@menthos.com> - - * configure.in: Added "mn" to ALL_LINGUAS. - -2003-01-21 Havoc Pennington <hp@redhat.com> - - * src/display.c (event_callback): only hop window to the current - workspace if the window was previously minimized. Should keep - mozilla from popping windows over to your current workspace. - -2003-01-20 Havoc Pennington <hp@redhat.com> - - Attempt to fix #85916 - - * src/keybindings.c (primary_modifier_still_pressed): new function - (handle_workspace_switch): handle modifier release prior to - getting the grab - (do_choose_window): handle modifier release prior to getting the - grab - - * src/keybindings.c (grab_keyboard): properly return failure - if the GrabKeyboard doesn't work - -2003-01-19 Havoc Pennington <hp@pobox.com> - - * configure.in: add note about how this is the unstable branch, - set version to 2.5.0 - -2003-01-14 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_maximize, meta_window_unmaximize) - (meta_window_make_fullscreen, meta_window_unmake_fullscreen): - recalc_window_features() after making these changes, should fix - #103317 - -2003-01-14 Rob Adams <robadams@ucla.edu> - - * src/prefs.c: Increase the number of run_command bindings in - screen_bindings from 12 to 32. - - * src/prefs.h: Increase the number of META_KEYBINDING_COMMAND_N - macros from 12 to 32. - - * src/keybindings.c: Increase the number of run_command handlers - from 12 to 32. - -2003-01-11 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_handle_mouse_grab_op_event): implement - compression of motion events (drop all but the most recently - received), guessing at fixes for #103009 - -2003-01-11 Havoc Pennington <hp@pobox.com> - - * configure.in: add ability to --disable-shape - -2003-01-11 Akira TAGOH <tagoh@gnome.gr.jp> - - * configure.in: fix the behavior of --enable-*. - -2003-01-10 Havoc Pennington <hp@redhat.com> - - * src/Makefile.am (desktopfiles_in_files): revert that change, I - got the wrong .desktop file. doh. - -2003-01-10 Havoc Pennington <hp@redhat.com> - - * src/Makefile.am (desktopfiles_DATA): don't install .desktop file - for properties dialog if we aren't building/installing the - properties dialog. - -2003-01-10 Havoc Pennington <hp@pobox.com> - - * NEWS: update - - * configure.in: bump to 2.4.13, require 2.2.0 for multihead - -2003-01-09 James M. Cape <jcape@ignore-your.tv> - - * src/themes/Esco/metacity-theme-1.xml: Use a line for the titlebar - text bg. - -2003-01-09 Havoc Pennington <hp@redhat.com> - - * src/window.c (recalc_window_features): argh, we were making all - dialogs skip taskbar; when did that get added. Fix to match - libwnck, only skip taskbar when the dialog is transient for some - other app window. - -2003-01-09 Havoc Pennington <hp@redhat.com> - - * src/metacity.schemas.in: change Windows+click back to Alt+click, - Windows+click just surprised everybody and didn't work half the - time. Maya users can configure it, and GTK DND can change its - default. - -2003-01-08 Havoc Pennington <hp@pobox.com> - - * src/metacity.schemas.in: assign Alt+F12 to shade window, - per #102658 - -2003-01-07 Havoc Pennington <hp@pobox.com> - - * src/screen.c (update_num_workspaces): fix off-by-one, patch from - readams@hmc.edu, #102806 - -2003-01-06 Arvind Samptur <arvind.samptur@wipro.com> - - * src/window.c: (constrain_position) don't apply - offscreen height difference. This would get the - window under the panel on a resize or a move. - Fixes #102418 - -2003-01-05 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_calc_workspace_layout): invert - vertical_workspaces cases (we want to go down each column if - it's vertical, and across each row if horizontal). Patch - from readams@hmc.edu - -2003-01-05 Pablo Saratxaga <pablo@mandrakesoft.com> - - * configure.in: Added Macedonian (mk) to ALL_LINGUAS - -2003-01-05 Havoc Pennington <hp@pobox.com> - - * src/frames.c (meta_frames_apply_shapes): put in the - HAVE_GTK_MULTIHEAD conditionals so we build with GTK 2.0 - -2003-01-05 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_show): focus new windows even in - mouse focus mode, #89981, patch from readams@hmc.edu - -2003-01-05 Havoc Pennington <hp@pobox.com> - - * src/workspace.c (meta_workspace_get_neighbor): redo using new - calc_workspace_layout to fix #98302 - - * src/util.c (topic_name): shorten default prefix - - * src/screen.c (meta_screen_calc_workspace_layout): enhance this - to handle all the funky layouts and calculate more information - than before - -2003-01-05 Pauli Virtanen <pauli.virtanen@hut.fi> - - * configure.in (ALL_LINGUAS): Added "fi" (Finnish). - -2003-01-05 Havoc Pennington <hp@pobox.com> - - * src/frames.c (meta_frames_apply_shapes): handle - the client having a shape mask, fixes #101806 - - * src/core.c (meta_core_get_client_xwindow): new function - - * src/frame.c, src/frame.h: keep a flag for whether we need to - update the frame shape - - * src/window.c (meta_window_new): select for ShapeNotify - - * src/display.h, src/display.c: actually query the shape - extension, instead of just using it all over the place. - - * src/prefs.c (update_application_based): don't let people turn on - application_based, as it just causes funky bugs. We can reenable - the pref when/if it ever does something useful. - -2003-01-03 Havoc Pennington <hp@redhat.com> - - * src/display.c: include the Xrandr header file - - * src/window.c (meta_window_fill_horizontal) - (meta_window_fill_vertical): maximize to work area, not entire - screen. doh. - -2002-12-19 Ross Burton <ross@burtonini.com> - - * doc/metacity-theme.dtd: Fix a typo and loosen the requirements - for the resize element. - -2002-12-19 Havoc Pennington <hp@pobox.com> - - * Reverted visual bell patch, #99886 - -2002-12-19 Yanko Kaneti <yaneti@declera.com> - - * configure.in: (ALL_LINGUAS) Added Bulgarian (bg). - -2002-12-18 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_new): select ColormapChangeMask - on toplevel windows, maybe a partial fix for #101478 - -Tue Dec 17 17:50:19 2002 HideToshi Tajima <hidetoshi.tajima@sun.com> - - * src/themes/AgingGorilla/metacity-theme-1.xml: added support for - border only windows. #100984. - -2002-12-17 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_begin_grab_op): don't use "(null)" - for null pointers, use "none", so I can distinguish - glibc-generated (null) which is a bug. - (key_event_description): ditto - (meta_display_begin_grab_op): ditto - - * src/window.c (update_sm_hints): ditto - - * src/keybindings.c (reload_modmap): ditto - (meta_display_process_key_event): ditto - -2002-12-17 Havoc Pennington <hp@pobox.com> - - * src/metacity.schemas.in: s/focussed/focused/ - -2002-12-17 Havoc Pennington <hp@pobox.com> - - * src/xprops.c (validate_or_free_results): add a comma to message #101401 - -2002-12-16 Bill Haneman <bill.haneman@sun.com> - - * configure.in: - Check for XKB extension. - - * src/Makefile.am: - Added bell.c and bell.h to metacity sources. - - * src/common.h: - (MetaFrameFlags): - Added META_FRAME_IS_FLASHING flag. - - * src/frame.h: - (MetaFrame): Added is_flashing field. - - * src/frame.c: - (meta_window_ensure_frame): - Initialize the is_flashing flag to FALSE. - (meta_frame_get_flags): - Handle the FRAME_IS_FLASHING flag. - (meta_window_destroy_frame): - Call meta_bell_notify_frame_destroy. - - * src/prefs.h: - (MetaPreference): - Added META_PREF_VISUAL_BELL, META_PREF_AUDIBLE_BELL, - META_PREF_VISUAL_BELL_TYPE. - (MetaVisualBellType): New enum. - (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): - (meta_prefs_get_visual_bell_type): - New accessor declarations. - - * src/prefs.c: - (#includes): Include "display.h", since we now call - meta_displays_list() in our update func. - (#defines): - Define KEY_VISUAL_BELL, KEY_AUDIBLE_BELL, - and KEY_VISUAL_BELL_TYPE. - (provide_visual_bell, bell_is_audible, visual_bell_type): - New static state variables. - (update_visual_bell): New method to update visual-bell - boolean settings from keys "visual_bell" and "audible_bell". - (update_visual_bell_type): - New method to update visual-bell type setting. - (visual_bell_type_from_string) : - New method to convert from gconf string to visual-bell - type enum. Only currently recognized values are "fullscreen" - and "frame_flash". - (change_notify): - Handle changes to visual and audible bell properties. - (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): - (meta_prefs_get_visual_bell_type): - New accessor definitions. - (meta_prefs_init): Added a second call to notify_add, - listens to "/desktop/gnome/interface" as well as "apps/metacity". - Also call the update funcs for the new visual-bell gconf keys. - (meta_preference_to_string): - Handle the visual/audible bell cases. - - * src/bell.h: - (meta_bell_notify); - New method, calls a visual notifucation - method based on the visual-bell-type, or none if the type - is unrecognized or invalid. - (meta_bell_set_audible): - New public method for setting the audible bell setting, - used in updater for new gconf key "audible_bell". - (meta_bell_init): - Initialize the bell notification for a display. - (meta_bell_shutdown): - Shutdown the bell notification for a display. - (meta_bell_notify_frame_destroy): - Remove pending idle handlers on notification. - - * src/bell.c: - Include "bell.h", and conditionally include <Xll/Xkblib.h>. - (meta_bell_set_audible): - If XKB is present, enable/disable the audible system - bell based on the gconf key /desktop/gnome/interface/audible_bell. - (meta_bell_init): - Query and initialize XKB if present, register for notification - on the bell, and set audible bell according to gconf settings. - (meta_bell_flash_screen): - Maps and unmaps a fullscreen X window (painted white, then - black), which causes a fullscreen 'flash' transient. - (meta_bell_flash_window_frame): - Flashes the titlebar of a specified window. - (meta_bell_flash_frame): - Calls meta_bell_flash_window_frame on the window which - was the source of the current bell event, or the currently - focussed window if the event source cannot be determined. - (meta_bell_unflash_frame): - Restore the frame's appearance to normal. - (meta_bell_flash_fullscreen): - Call meta_bell_flash_fullscreen for all screens. - (meta_bell_shutdown): - New method. - (meta_bell_notify_frame_destroy): - Remove pending idle handlers on notification, - testing for frame->is_flashing first. - - * src/display.h: - (MetaDisplay): Added xkb_base_event_type field. - - * src/display.c: - Check for XKB and include "X11/XKBlib.h" if present. - (meta_display_open): Call meta_bell_init. - (event_callback): Call meta_bell_notify - when event comes from XKB and is XkbBellNotify - (prefs_changed_callback): - Handle META_PREF_AUDIBLE_BELL notification. - - * src/screen.h: - (MetaScreen): Add flash_window field. - - * src/screen.c: - (meta_screen_new): - Initialize flash_window field. - - * src/theme.c: - (theme_get_style): - New heuristic for focus-style, to invert sense of focus - flag when META_FRAME_IS_FLASHING flag is set. - - * src/metacity.schemas.in: - Added scheme information for - /apps/metacity/general/visual_bell, - /apps/metacity/general/audible_bell, and - /apps/metacity/general/visual_bell_type. - -2002-12-16 Havoc Pennington <hp@pobox.com> - - * src/window-props.c (init_wm_name): argh, screwed that up. get - WM_NAME as VALUE_TEXT_PROPERTY #101383 - -2002-12-16 Bill Haneman <bill.haneman@sun.com> - - * configure.in: - Check for XKB extension. - - * src/Makefile.am: - Added bell.c and bell.h to metacity sources. - - * src/common.h: - (MetaFrameFlags): - Added META_FRAME_IS_FLASHING flag. - - * src/frame.h: - (MetaFrame): Added is_flashing field. - - * src/frame.c: - (meta_window_ensure_frame): - Initialize the is_flashing flag to FALSE. - (meta_frame_get_flags): - Handle the FRAME_IS_FLASHING flag. - (meta_window_destroy_frame): - Call meta_bell_notify_frame_destroy. - - * src/prefs.h: - (MetaPreference): - Added META_PREF_VISUAL_BELL, META_PREF_AUDIBLE_BELL, - META_PREF_VISUAL_BELL_TYPE. - (MetaVisualBellType): New enum. - (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): - (meta_prefs_get_visual_bell_type): - New accessor declarations. - - * src/prefs.c: - (#includes): Include "display.h", since we now call - meta_displays_list() in our update func. - (#defines): - Define KEY_VISUAL_BELL, KEY_AUDIBLE_BELL, - and KEY_VISUAL_BELL_TYPE. - (provide_visual_bell, bell_is_audible, visual_bell_type): - New static state variables. - (update_visual_bell): New method to update visual-bell - boolean settings from keys "visual_bell" and "audible_bell". - (update_visual_bell_type): - New method to update visual-bell type setting. - (visual_bell_type_from_string) : - New method to convert from gconf string to visual-bell - type enum. Only currently recognized values are "fullscreen" - and "frame_flash". - (change_notify): - Handle changes to visual and audible bell properties. - (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): - (meta_prefs_get_visual_bell_type): - New accessor definitions. - (meta_prefs_init): Added a second call to notify_add, - listens to "/desktop/gnome/interface" as well as "apps/metacity". - Also call the update funcs for the new visual-bell gconf keys. - (meta_preference_to_string): - Handle the visual/audible bell cases. - - * src/bell.h: - (meta_bell_notify); - New method, calls a visual notifucation - method based on the visual-bell-type, or none if the type - is unrecognized or invalid. - (meta_bell_set_audible): - New public method for setting the audible bell setting, - used in updater for new gconf key "audible_bell". - (meta_bell_init): - Initialize the bell notification for a display. - (meta_bell_shutdown): - Shutdown the bell notification for a display. - (meta_bell_notify_frame_destroy): - Remove pending idle handlers on notification. - - * src/bell.c: - Include "bell.h", and conditionally include <Xll/Xkblib.h>. - (meta_bell_set_audible): - If XKB is present, enable/disable the audible system - bell based on the gconf key /desktop/gnome/interface/audible_bell. - (meta_bell_init): - Query and initialize XKB if present, register for notification - on the bell, and set audible bell according to gconf settings. - (meta_bell_flash_screen): - Maps and unmaps a fullscreen X window (painted white, then - black), which causes a fullscreen 'flash' transient. - (meta_bell_flash_window_frame): - Flashes the titlebar of a specified window. - (meta_bell_flash_frame): - Calls meta_bell_flash_window_frame on the window which - was the source of the current bell event, or the currently - focussed window if the event source cannot be determined. - (meta_bell_unflash_frame): - Restore the frame's appearance to normal. - (meta_bell_flash_fullscreen): - Call meta_bell_flash_fullscreen for all screens. - (meta_bell_shutdown): - New method. - (meta_bell_notify_frame_destroy): - Remove pending idle handlers on notification, - testing for frame->is_flashing first. - - * src/display.h: - (MetaDisplay): Added xkb_base_event_type field. - - * src/display.c: - Check for XKB and include "X11/XKBlib.h" if present. - (meta_display_open): Call meta_bell_init. - (event_callback): Call meta_bell_notify - when event comes from XKB and is XkbBellNotify - (prefs_changed_callback): - Handle META_PREF_AUDIBLE_BELL notification. - - * src/screen.h: - (MetaScreen): Add flash_window field. - - * src/screen.c: - (meta_screen_new): - Initialize flash_window field. - - * src/theme.c: - (theme_get_style): - New heuristic for focus-style, to invert sense of focus - flag when META_FRAME_IS_FLASHING flag is set. - - * src/metacity.schemas.in: - Added scheme information for - /apps/metacity/general/visual_bell, - /apps/metacity/general/audible_bell, and - /apps/metacity/general/visual_bell_type. - -2002-12-16 Havoc Pennington <hp@pobox.com> - - * src/window-props.c: use META_PROP_VALUE_STRING_AS_UTF8 so - we convert old Latin-1 WM_NAME to UTF-8 - - * src/xprops.h (enum): add META_PROP_VALUE_STRING_AS_UTF8 to get a - latin1 string then convert. - -2002-12-15 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_new): get window name before anything - else. - - * src/xprops.c (validate_or_free_results): instead of suggesting - how to get window title etc. with xprop, just print out the - window title. much better. - -2002-12-15 Havoc Pennington <hp@pobox.com> - - * src/xprops.c (validate_or_free_results): make the warning about - strange property contents blame the application and explain how to - use xprop to diagnose which app is causing the problem. - -2002-12-15 Havoc Pennington <hp@pobox.com> - - * src/prefs.c (meta_prefs_change_workspace_name): don't pass NULL - string to gconf_client_set_string #101237 - -2002-12-13 Havoc Pennington <hp@redhat.com> - - * src/tools/Makefile.am (Desktop_in_files): only install .desktop - file for metacity-properties if we actually install - metacity-properties - - * src/display.c (event_callback): not focusing on button 2 click - was crack, revert that change. - -2002-12-09 Havoc Pennington <hp@pobox.com> - - * AUTHORS: add myself here, bug #100789 - - * src/display.c (meta_display_set_grab_op_cursor): drop - PointerMotionHintMask - - * src/window.c (meta_window_handle_mouse_grab_op_event): don't use - XQueryPointer, as we aren't using PointerMotionHint now - - * src/display.c (event_callback): rearrange a bit of code - for slight speedup and clarity - - * src/window.c (update_resize) - (meta_window_handle_mouse_grab_op_event): implement - usage of the _METACITY_UPDATE_COUNTER - (meta_window_handle_mouse_grab_op_event): fix code that - used event->xbutton with a motion event - - * src/display.c (meta_display_open): add new atoms, and - initialize Xsync if we have it - (grab_op_is_resizing): new function - (meta_display_begin_grab_op): create an alarm monitoring - window's _METACITY_UPDATE_COUNTER - (meta_spew_event): conditionalize this on WITH_VERBOSE_MODE - and print alarm events. - - * src/window.c (meta_window_new): fetch _METACITY_UPDATE_COUNTER - - * configure.in (HAVE_XSYNC): check for Xsync extension - -Mon Dec 9 22:09:56 2002 Soeren Sandmann <sandmann@daimi.au.dk> - - * src/display.c, src/window.c: Handle crossing events during - resizing. (#93384). - -2002-12-09 Havoc Pennington <hp@redhat.com> - - * configure.in: 2.4.8 - -2002-12-08 Havoc Pennington <hp@pobox.com> - - * README: updates - - * src/window.c (MAX_RESIZES_PER_SECOND): change to 20 instead of - 30, just as an experiment. - (MOVE_THRESHOLD): change 15 to 20 - (RESIZE_THRESHOLD): change 15 to 20 - - * src/util.c (ensure_logfile): kill this function when verbose - mode is disabled. - -2002-12-08 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_fill_vertical) - (meta_window_fill_horizontal): new functions to resize to - fill screen - - * src/keybindings.c: add vert, horiz maximize - - * src/prefs.c: had vert, horiz maximize - - * src/metacity.schemas.in: shorten some overlong short - descriptions that make the keybindings capplet look ugly. - Add maximize_vertically, maximize_horizontally keys. - -2002-12-08 Havoc Pennington <hp@pobox.com> - - * src/prefs.c (meta_prefs_get_application_based): make this always - return FALSE for now, to avoid bug reports. - - * src/util.c (ensure_logfile): put "opened log file" message on - stderr so it will normally land in ~/.xsession-errors - - * configure.in: remove extra AC_ARG_PROGRAM - - * src/display.c (event_callback): handle the toggle-verbose message - - * src/tools/metacity-message.c: add a toggle-verbose message, been - meaning to do this for a while. - - * src/util.c (meta_set_verbose): if verbose mode is enabled and we - don't support it, then exit. - - * src/prefs.c: allow building without gconf (currently means some - prefs are no-ops) - - * src/util.c, src/util.h: support defining macros to - kill all verbose output entirely. (Removes the code and strings - associated with it) - - * configure.in: don't get METACITY_PROPS_LIBS if not building the - config dialog. - (HAVE_GCONF): allow building sans gconf, if you are size-sensitive - and not using gnome. - (WITH_VERBOSE_MODE): add ability to disable all the verbose debug - spew strings, to shrink the binary. - (--disable-sm): allow SM support to be forced on or off - (--disable-startup-notification): allow forcing this on or off - -2002-12-08 Havoc Pennington <hp@pobox.com> - - * src/prefs.c (update_workspace_name): also treat empty string as - "unset" in this function. - -Thu Dec 5 18:41:02 2002 HideToshi Tajima <hidetoshi.tajima@sun.com> - - * src/window.h (META_WINDOW_IN_NORMAL_TAB_CHAIN, - META_WINDOW_IN_DOCK_TAB_CHAIN) : never use a window with input = - FALSE take_focus = FALSE in the normal and dock tab chains. #90409 - -Thu Dec 5 13:56:52 2002 HideToshi Tajima <hidetoshi.tajima@sun.com> - - * src/display.c (event_callback): move a window to the current - space on the MapRequest when it's not on the space yet. #100390 - -2002-12-01 Havoc Pennington <hp@pobox.com> - - * src/frames.c (get_control): rearrange this function a bit, so - that we return CONTROL_TITLE for anything above the bottom of the - titlebar, in the fallback case where no other control was found. - Also, don't return RESIZE_N for title rect above the top resize - size, unless the window is resizable. - (meta_frames_button_press_event): only start a move when clicking - control TITLE, not control NONE. This way you don't start moving - a nonresizable window if you click its edges. - -2002-12-01 Havoc Pennington <hp@pobox.com> - - * src/tools/Makefile.am: conditionalize building the config dialog - - * configure.in (BUILD_CONFIG_DIALOG): add --enable-config-dialog - option to turn on the "window focus" dialog. This is part of - deprecating this dialog. - -2002-11-30 Havoc Pennington <hp@pobox.com> - - * src/screen.c (STARTUP_TIMEOUT): lengthen to 15 seconds - - * src/util.c (utf8_fputs): hmm, return a value - - * src/screen.c (meta_screen_apply_startup_properties): new - function to apply initial workspace based on startup sequence. - - * src/window.c (meta_window_new): load _NET_STARTUP_ID - (meta_window_get_startup_id): new function - - * src/window-props.c (meta_display_init_window_prop_hooks): add - hooks for _NET_STARTUP_ID - - * src/display.c (event_callback): send property events to - groups. - - * src/xprops.c (meta_prop_get_values): make a type of INVALID - mean to ignore that property (don't fetch its value). - - * src/group.c (meta_group_property_notify): new function - - * src/screen.c (set_supported_hint): support _NET_STARTUP_ID - - * src/display.c (meta_display_open): add _NET_STARTUP_ID to atoms - we initialize - - * src/group-private.h: private header shared between - group-props.c, group.c - - * src/group-props.h, src/group-props.c: new files to contain - functions for retrieving group properties - - * src/window.c (meta_window_same_application): change this a bit - to work with new definition of group - - * src/group.c (meta_window_get_group): always create a group for - every window, using the window's own ID as group leader if - required. - - * src/window.c (update_wm_hints): handle changes to group leader - - * src/group.c (meta_window_group_leader_changed): new function - - * src/display.h (struct _MetaDisplay): _NET_WM_WINDOW_TYPE_SPLASH, - not SPLASHSCREEN. Reported by Gregory Merchan and Matthias Clasen. - - * src/screen.c (startup_sequence_timeout): when timing out a - startup sequence, send a remove message, don't just time it out - locally. - -2002-11-26 Calum Benson <calum.benson@sun.com> - - * src/themes/Crux : - - Removed alpha layers from the pixmaps that don't need them. - Fixes #98389, results in 10-15% speedup on most machines. - -2002-11-26 Glynn Foster <glynn.foster@sun.com> - - * configure.in: 2.4.5 - -2002-11-23 Dan Mills <thunder@ximian.com> - - * Makefile.am: remove theme-format.txt, it's now in doc/. - -2002-11-22 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_change_workspace): patch from - Hidetoshi Tajima to move a window's transients when moving - the window between workspaces. #98900 - -2002-11-21 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_open): init ret_to to - RevertToPointerRoot out of sheer paranoia; don't want no - RevertToNone in my code! - -2002-11-21 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_initial_workspace): delete - (meta_window_new): add getting initial workspace to the batch - property get call - - * src/window-props.c (meta_display_init_window_prop_hooks): add - net_wm_desktop and win_workspace support - -2002-11-20 Havoc Pennington <hp@pobox.com> - - * src/window-props.c (set_icon_title): remove unused variable - - * src/screen.c (meta_screen_new): read an existing - _NET_CURRENT_DESKTOP and restore it if set. Makes a restart even - less visible. - - * src/workspace.c (set_active_space_hint): don't set the hint - during the process of unmanaging a screen - -2002-11-20 Havoc Pennington <hp@pobox.com> - - * configure.in: add doc/Makefile - - * doc/metacity-theme.dtd: add DTD for themes from Ross Burton - - * doc/Makefile.am: doc subdir - - * doc/theme-format.txt: move to doc subdir - -2002-11-19 Havoc Pennington <hp@pobox.com> - - Should really fix #98303 - - * src/prefs.c (meta_prefs_change_workspace_name): add - bad hack to treat empty string the same as null - - * src/menu.c (get_workspace_name_with_accel): allocate one more - than the length of "name" so we have room for a nul byte (and - don't malloc(0) on empty strings). Also some formatting cleanups. - -2002-11-19 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_client_message): do a - recalc_window_features after setting new wm_state in order - to update skip_pager in addition to wm_state_skip_pager - (set_net_wm_state): base _NET_WM_STATE on skip_pager not - wm_state_skip_pager, ditto for skip_taskbar - -2002-11-19 Havoc Pennington <hp@pobox.com> - - Fix #98303 and assorted cleanup - - * src/prefs.c (meta_preference_to_string): handle - META_PREF_WORKSPACE_NAMES - - * src/menu.c (get_workspace_name_with_accel): assert that the - workspace has a name - - * src/screen.c (meta_screen_ensure_workspace_popup): assert that - we got a workspace name - (meta_screen_ensure_workspace_popup): assert that we got a - workspace name - - * src/prefs.c (update_workspace_name): fix screwiness (strcmp with - a freed string, assorted bad logic) - (init_workspace_names): assert that we filled in a default - workspace name - (meta_prefs_get_workspace_name): assert non-NULL workspace name - -2002-11-16 Bill Haneman <bill.haneman@sun.com> - - * src/themes/Atlanta/metacity-theme-1.xml: - Changed outer bevel and focus line color to - work better with inverse themes (no effect on - Default or other existing gtk+ themes). - -2002-11-13 Havoc Pennington <hp@pobox.com> - - * src/ui.c (get_cmap): fix a multihead safety thing (use proper - system colormap for the drawable's screen) - -Thu Nov 14 17:30:10 2002 Jonathan Blandford <jrb@gnome.org> - - * src/Makefile.am (libmetacityinclude_HEADERS): include common.h. - -2002-11-12 Havoc Pennington <hp@pobox.com> - - * src/theme.c (draw_op_as_pixbuf): don't read from op->data.image - when the op is an icon - -2002-11-12 Havoc Pennington <hp@redhat.com> - - * src/stack.c (meta_stack_get_default_focus_window): never use a - window with input = FALSE take_focus = FALSE as the default focus - window #95454 fix from Hidetoshi Tajima - -2002-11-10 James M. Cape <jcape@ignore-your.tv> - - * src/themes/Esco/metacity-theme-1.xml: Major changes - to look of theme. I'd also recommend "minimize,maximize:close" - for the button_layout, it looks really slick :-). - -2002-11-08 Mark McLoughlin <mark@skynet.ie> - - * src/workspace.c: - (meta_motion_direction_to_string), - (meta_screen_corner_to_string): impl for nice debugging. - (meta_workspace_get_neighbor): fix broken logic and - cleanup debugging. - -Thu Nov 7 17:07:21 2002 Jonathan Blandford <jrb@redhat.com> - - * src/libmetacity-private.pc.in: add a pc file for - libmetacity-private - - * src/Makefile.am: Install a few files as a shared library so that - others can draw metacity themes. - -2002-11-06 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (grab_keys): push an error trap around the - whole window-key-grab loop - (ungrab_all_keys): avoid requiring return value from the error - trap, unless in debugging mode - (regrab_window_bindings, regrab_screen_bindings): push traps - around the loops, for efficiency - - * src/display.c (event_callback): fix from Padraig O'Briain to - compress extra MappingNotify events to avoid extra work. - -2002-11-05 Calum Benson <calum.benson@sun.com> - - * src/themes/Crux/active-restore-button.png: - * src/themes/Crux/inactive-restore-button.png: - * src/themes/Crux/metacity-theme-1.xml: add a restore button - for maximized windows, and un-hard-code titlebar text colors. - Fixes #97759. - -2002-11-05 Havoc Pennington <hp@redhat.com> - - * src/workspace.c (meta_workspace_get_neighbor): apply patch from - Nikos Mouat to fix this function - -2002-11-04 Havoc Pennington <hp@pobox.com> - - * src/theme.c (scale_and_alpha_pixbuf): fix bug I introduced in - case where scaling was done in both directions. - -2002-11-04 Havoc Pennington <hp@pobox.com> - - Patch from Brian Cameron to implement the vertical/horizontal - striped image accelerated scaling from the gtk pixbuf engine. - - * src/theme.c (scale_and_alpha_pixbuf): if an image is - vertical/horizontal stripes, use special extra-fast scaling - routines. - - * src/theme-parser.c (parse_draw_op_element): when loading an - image, mark it as vertically/horizontally striped when appropriate - -2002-11-04 Erwann Chenede - <erwann.chenede@sun.com> - - * src/xprops.c (meta_prop_get_values): changed __FUNCTION__ - to G_GNUC_FUNCTION as __FUNCTION__ is not portable. - -2002-11-03 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_grab): remove XSync calls from here - (meta_display_ungrab): remove XSync from here, but put in - an XFlush to be sure we get the ungrab sent. - - * src/util.c (meta_topic): track sync count here - - * src/errors.c: move sync count out of here - - Throughout: error spew on all XSync() calls - - * src/run-metacity.sh: don't set METACITY_DEBUG - -2002-11-03 Havoc Pennington <hp@pobox.com> - - * src/window-props.c (meta_display_init_window_prop_hooks): add - _NET_WM_NAME, WM_NAME, _NET_WM_ICON_NAME, WM_ICON_NAME support - - * src/window.c (meta_window_new): use window-props.h for - _NET_WM_NAME, WM_NAME, _NET_WM_ICON_NAME, WM_ICON_NAME - -2002-11-03 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_new): use window-props.h stuff for a - couple of properties - (implement_showing): fix printf string - - * src/xprops.c (meta_prop_free_values): new function - - * src/window-props.h, src/window-props.c: start moving code that - handles loading window properties into this file. - -2002-11-03 Havoc Pennington <hp@pobox.com> - - * src/stack.c (create_constraints): filter out windows that aren't - in the stack for whatever reason, avoids a crash - -2002-11-03 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_calc_showing): split into "see if we - should be showing" and "actually show/hide" functions - (idle_calc_showing): rework to first unmap all newly-hidden - windows from bottom to top then map all newly-showing windows from - top to bottom resulting in fewer exposes, #95220 - -2002-11-03 Havoc Pennington <hp@pobox.com> - - * src/theme.c (meta_frame_layout_calc_geometry): fix from Garrett - LeSage for which button backgrounds we draw when - -2002-11-03 Havoc Pennington <hp@pobox.com> - - * src/workspace.c (meta_workspace_get_name): new function, - and remove workspace->name field, instead just get the - name from prefs each time - - * src/screen.c (meta_screen_update_workspace_names): update the - gconf key to persist workspace names here, instead of changing - the names we use - - * src/util.c (topic_name): add META_DEBUG_PREFS - - * src/prefs.c: change NUM_COMMANDS to 32 to allow more custom - commands, implement workspace names - - * src/metacity.schemas.in: add workspace_names/name_NN gconf keys. - -2002-11-01 Christian Neumair <chris@gnome-de.org> - - * configure.in: We want at least autoconf 2.5. - -2002-10-29 Havoc Pennington <hp@pobox.com> - - * configure.in: 2.4.3, why not - -2002-10-28 Havoc Pennington <hp@redhat.com> - - * src/window.c (update_size_hints): use meta_prop_get_size_hints - - * src/xprops.c: add support for getting XSizeHints - -2002-10-28 Havoc Pennington <hp@pobox.com> - - * src/window.c, src/display.c: store the window menu on the - display and blow it away when a window closes, so we don't - get funny stuck menus. Patch from Martin Garton #87514 - -2002-10-27 Anders Carlsson <andersca@gnu.org> - - * configure.in: Make XRandr detection work better. - -2002-10-27 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_free): move - meta_window_shutdown_group() much earlier in the destroy process. - May fix #96928 tracked down by Kjartan Maraas and Martin Garton. - - * src/group.c (meta_window_get_group): never add window to a group - after we've started unmanaging the window - -2002-10-26 Havoc Pennington <hp@pobox.com> - - * src/iconcache.c: include config.h - - * src/group.c: include config.h - - * src/frame.c: include config.h - - * src/core.c: include config.h so it doesn't crash all over the - place due to #ifdef HAVE_STARTUP_NOTIFICATION - - * src/util.c (meta_print_backtrace): export from this file - - * src/main.c (log_handler): print backtrace here - -2002-10-26 Havoc Pennington <hp@pobox.com> - - * src/wm-tester/main.c (evil_timeout): make windows randomly - transient for each other http://bugzilla.gnome.org/show_bug.cgi?id=96928 - -2002-10-26 Havoc Pennington <hp@pobox.com> - - * src/xprops.c (meta_prop_get_text_property): new function - (meta_prop_get_wm_hints): new function - (meta_prop_get_class_hint): new function - -2002-10-26 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_new): use multi-value-get on a couple - of properties for testing - - * src/xprops.c (meta_prop_get_values): implement multi-value-get - - * src/window.c (update_mwm_hints): XFree motif hints as we changed - it to use Xmalloc - - * src/xprops.c: massively rework this to set up a - get-multiple-properties-at-once API. - - * src/async-getprop.c (ag_Xmalloc): new function - -2002-10-25 Havoc Pennington <hp@pobox.com> - - Add "busy cursor on app startup" support, conditionally - works - only if libstartup-notification is found, and in practice requires - a GTK patch that's not in yet. - - * src/screen.c: monitor startup events and set busy cursor if - appropriate - - * src/display.c (meta_display_open): create SnDisplay - - * configure.in: check for startup notification, - and add the cute "configure summary" at the end - -2002-10-24 Havoc Pennington <hp@redhat.com> - - * src/theme.c (meta_frame_layout_calc_geometry): if only one - right-corner button, use right_right_background not - right_left_background - -2002-10-24 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_get_icon_geometry): make public - - * src/screen.c (meta_screen_ensure_tab_popup): put the alt+tab - highlight-window indicator on the icon, not the window itself, - if the window is minimized. - -2002-10-24 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_get_tab_list): put minimized windows - at the end of Alt+Tab, #89416 - -2002-10-23 Havoc Pennington <hp@redhat.com> - - * src/theme.c (meta_frame_layout_calc_geometry): initialize the - left button background rectangles. - -2002-10-21 Havoc Pennington <hp@redhat.com> - - Optimizations for managing new windows (do not all take effect if - METACITY_DEBUG=1). Bug #96404 - - * src/keybindings.c (meta_change_keygrab): use error trap nesting - and conditionalize on meta_is_verbose() to avoid a ton of XSync - - * src/display.c (meta_change_button_grab): ditto - - Throughout: move to new error trap setup to save on XSync calls, - new setup is: - - * src/errors.c (meta_error_trap_push_with_return): new function, - an error trap that needs to care about return value and thus - sync even if an outer trap still exists - (meta_error_trap_pop_with_return): new function - (meta_error_trap_pop): add "last_request_was_roundtrip" - argument allowing us to avoid XSync() if we just did - a GetProperty or whatever. - - * src/util.c (meta_warning): flush the warning file descriptor - - * src/Makefile.am (INCLUDES): define G_LOG_DOMAIN - -2002-10-20 Havoc Pennington <hp@pobox.com> - - * src/ui.c (meta_image_window_new): put multihead stuff in - HAVE_GTK_MULTIHEAD, reported by John Palmieri - -2002-10-20 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (handle_raise_or_lower): check above->mapped - before deciding if it overlaps the window being raiselowered, - fix from Stephane Chauveau - -2002-10-19 Jeremy Katz <katzj@redhat.com> - - * configure.in: make Xrandr check less noisy - -2002-10-18 Havoc Pennington <hp@redhat.com> - - * src/effects.c (meta_effects_draw_box_animation): call - meta_image_window_new in multihead-safe way - - * src/ui.c (meta_image_window_new): multihead safety - -2002-10-18 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_refresh_resize_popup): only create the - resize popup if width_inc or height_inc are > 1 - - * src/resizepopup.c: Clear out all the weird tickmark cruft, - saves us about 2.5K of binary size, whee - (meta_ui_resize_popup_new): take display/screen arguments and make - multihead-safe #94349 - -2002-10-18 Havoc Pennington <hp@redhat.com> - - * src/keybindings.c (do_choose_window): don't start the cycle - process if the binding for switching windows has no modifier bits, - just focus the window immediately. - - * src/prefs.c, src/keybindings.c: add a keybinding to move between - windows that goes in the opposite direction. This is mostly - useful if you want to bind unmodified keys to the switch windows - functions, e.g. if you have "Forward" and "Back" keys on your - keyboard. Patch from Shilad Sen <shilad sourcelight com> - -2002-10-18 Havoc Pennington <hp@redhat.com> - - * src/prefs.c, src/frames.c: add "what happens when you double - click the titlebar" setting, patch from Sean Middleditch bug - #95625. This is basically an "add Windows emulation mode" patch. - -2002-10-18 Havoc Pennington <hp@redhat.com> - - * src/metacity.schemas.in: move window-click to Super+click not - Alt+click by default. Super should be the Windows key on keyboards - that have one and are so configured. Prepare for the FAQ on this. - -2002-10-18 Havoc Pennington <hp@redhat.com> - - * src/window.c (constrain_size): fix min aspect handling, - patch from Martin Garton #94943 - -2002-10-18 Andras Timar <timar@gnome.hu> - - * configure.in: Added hu to ALL_LINGUAS. - -2002-10-18 Havoc Pennington <hp@pobox.com> - - * src/stack.c (constrain_stacking): replace the old - apply_constraints with wacky new approach involving graphing all - the constraints then walking the graph. Fixes #94876 and probably - other stacking bugs as well, thanks to Arvind for tracking down - the issue. - - (compute_layer): add FIXME and reference to bug #96140 - -2002-10-17 Havoc Pennington <hp@redhat.com> - - * src/stack.c (apply_constraints): don't place - transient-for-whole-group windows above _each other_, only - above other windows in the group that aren't themselves - transient-for-whole-group. Should help with part of #94876 - -2002-10-17 Havoc Pennington <hp@redhat.com> - - * src/stack.c (apply_constraints): fix memory leak of - group_windows, and don't use the variable name "tmp" twice. Shadow - variables bad. - -2002-10-17 Havoc Pennington <hp@redhat.com> - - * src/tools/metacity-window-demo.c (dialog_cb): add code to create - big stacks of dialogs transient for each other, for testing. - -2002-10-16 Havoc Pennington <hp@redhat.com> - - * src/workspace.c: workspaces are all per-screen now, fix - accordingly - - * src/core.c: fix multihead workspace stuff - - * src/keybindings.c: multihead-rama - - * src/screen.c (meta_screen_show_desktop): new functions to - replace display equivalents - - * src/display.c (meta_display_get_workspace_by_screen_index): get - rid of this - (meta_display_get_workspace_by_index): get rid of this - (event_callback): handle _NET_SHOWING_DESKTOP message per-screen - - * src/screen.c (meta_screen_get_workspace_by_index): new function - - * src/screen.h (struct _MetaScreen): move workspace list, and - showing_desktop flag, to be per-screen - - * src/window.c (window_query_root_pointer): return whether pointer - is on window's screen - (meta_window_handle_mouse_grab_op_event): don't use coordinates - from other screens when updating a window operation on the current - screen. I can't believe no one has reported this... - -2002-10-16 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_client_message): update window layer - when above/below state is changed. Fixed by Ross Burton. - -2002-10-14 Federico Mena Quintero <federico@ximian.com> - - * src/display.c (event_callback): Ignore EnterNotify events when - the detail field is set to NotifyInferior. Fixes #95747. - -2002-10-12 Havoc Pennington <hp@pobox.com> - - * src/metacity.schemas.in: button layout key - - * src/prefs.c: Add button layout gconf key - (change_notify): use some "else if" instead of "if" where we - should have been - -2002-10-11 Havoc Pennington <hp@redhat.com> - - * src/display.c (event_callback): don't raise window on button 2 - click, only on button 1 and button 3. - - * src/frames.c (meta_frames_button_press_event): lower on button 2 - press on frame - - * src/core.c (meta_core_user_lower): new function - -2002-10-11 Havoc Pennington <hp@pobox.com> - - * src/stack.c (window_is_fullscreen_size): make the checks here - allow windows larger than the screen in addition to - exactly-screen-size - - * src/window.c (meta_window_configure_request): delete the "try to - auto-enter-fullscreen-state" hack here, because it was broken, and - the changes to the stacking code to move screen-size focused - windows to the fullscreen layer should work better. - (meta_window_new): remove auto-fullscreen hack from here too - -2002-10-09 Havoc Pennington <hp@pobox.com> - - * src/stack.c (apply_constraints): also keep utility/menu/toolbar - windows above their whole group. - - (get_standalone_layer): don't use META_LAYER_FOCUSED_WINDOW, but - only use META_LAYER_FULLSCREEN while the fullscreen window has - focus. Also, put screen-sized windows in the fullscreen layer, - even if we didn't dare to actually put them in the fullscreen - state. - -2002-10-07 Havoc Pennington <hp@redhat.com> - - Add a modifier key preference for the Alt+click stuff. - Can be set to "disabled" as well. - - * src/run-metacity.sh: load .Xmodmap in the Xnest if it exists - - * src/display.c (meta_display_ungrab_window_buttons): ungrab - AnyModifier in case the modifier changed since we grabbed - (meta_display_open): rearrange code to use meta_display_close() to - mop up when we can't find any screens, avoiding the need to - keep the bail-out code in sync with meta_display_close. - - * src/keybindings.c (devirtualize_modifiers): move this function - to a public place in display.c - - * src/metacity.schemas.in: add setting for the modifier key - to use for Alt+left/middle/right click. - - * src/prefs.c (update_binding): add a missing newline to a warning - (meta_prefs_get_mouse_button_mods): new function - - * src/ui.c (meta_ui_parse_modifier): new function - -2002-10-07 Havoc Pennington <hp@pobox.com> - - * src/async-getprop.c: don't include unportable Xproto.h, fix from - Glynn Foster. - -2002-10-06 Havoc Pennington <hp@pobox.com> - - * src/async-getprop.c: change to add only one _XAsyncHandler per - display, speeding things up a bit. - -2002-10-06 Havoc Pennington <hp@pobox.com> - - * src/async-getprop.c: Add wacky hack suggested by Keith Packard - to get X properties asynchronously. Not actually used by metacity - yet, but thinking about it. - -2002-10-04 Havoc Pennington <hp@redhat.com> - - * configure.in: actually link to RANDR_LIBS - -2002-10-04 Havoc Pennington <hp@redhat.com> - - * src/display.c (event_callback): do XRRUpdateConfiguration() - if we have RandR extension, else poke in Xlib's screen struct to - update the screen size. - - * configure.in: fix a bogus overwrite of cppflags, - add a check for RandR extension - -2002-10-04 Arvind Samptur <arvind.samptur@wipro.com> - - * src/window.c (meta_window_change_workspace): call - meta_window_unstick before adding window to workspace. - (menu_callback): call meta_workspace_activate before - meta_window_change_workspace. This would avoid us running an - extra loop for determining the window workspace list. - - Patches from Jeyasudha and Arvind. Fixes #92575 - -2002-10-03 Havoc Pennington <hp@pobox.com> - - * src/themes/Esco/metacity-theme-1.xml: only specify the - middle backgrounds, let left/right fall back to middle - - * src/theme.c (get_button): fall back to middle_background draw - routines when missing the left/right button backgrounds. - (button_rect): fix to handle drawing middle button backgrounds - (meta_frame_style_draw): draw middle background once per middle - button - -2002-10-03 Havoc Pennington <hp@pobox.com> - - Button-reordering patch. Has all the code except actually - installing a gconf schema and reading the gconf key in prefs.c. - metacity-theme-viewer displays the button layouts for testing - themes. - - * src/preview-widget.c (meta_preview_size_request): make up a - width/height if no child widget - - * src/prefs.c (meta_prefs_get_button_layout): new function - - * src/frames.c: get the button layout from prefs and - use it when drawing - - * src/theme.c (meta_frame_layout_calc_geometry): enhance to be - able to lay out buttons in different arrangements - (button_rect): draw the new button background rectangles - (meta_theme_draw_frame): require a button layout argument - (meta_theme_calc_geometry): pass in the button layout - - * src/preview-widget.h: mod to handle button layouts - - * src/theme-viewer.c: mod to handle button layouts - -2002-10-03 Havoc Pennington <hp@redhat.com> - - * configure.in: 2.4.2 - -2002-10-03 Havoc Pennington <hp@redhat.com> - - * src/window.c (check_moveresize_frequency): handle the case where - the clock is set backward - -2002-10-01 Havoc Pennington <hp@pobox.com> - - * src/place.c (find_next_cascade): try extra cascades alongside - the first, if the first fails; patch from readams@hmc.edu - -2002-10-01 Havoc Pennington <hp@pobox.com> - - * src/stack.c (get_standalone_layer): put ABOVE windows in same - layer as docks. - -2002-10-01 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_resize_func): make it static - - * src/stack.c (get_standalone_layer): put above/below windows - in an appropriate layer. - - * src/screen.c (set_supported_hint): say we support above/below - - * src/display.h (struct _MetaDisplay): add _NET_WM_STATE_ABOVE, - _NET_WM_STATE_BELOW atoms - - * src/window.c (meta_window_client_message): handle above/below - state messages - (set_net_wm_state): handler above/below state - (update_net_wm_state): handle above/below states - -2002-10-01 Mark McLoughlin <mark@skynet.ie> - - * src/screen.c: (meta_screen_new): default to - topleft starting corner. - (meta_screen_update_workspace_layout): handle - new property format : orient,x,y,starting corner. - Fixes #89373. - - * src/screen.h: add MetaScreenCorner enum. - -2002-10-01 Havoc Pennington <hp@pobox.com> - - * src/window.c (constrain_position): always align fullscreen - windows to top, as we do with maximized windows. - -2002-10-01 Stanislav Brabec <sbrabec@suse.cz> - - * configure.in: Added cs to ALL_LINGUAS. - -2002-09-30 Havoc Pennington <hp@pobox.com> - - * src/screen.c (reload_xinerama_infos): fix compilation on - Solaris, patch from Satyajit Kanungo - -2002-09-29 Havoc Pennington <hp@pobox.com> - - * src/eggaccelerators.c: update from libegg to get fix from Ralph - Loader for <Super> <Hyper> <Meta> parsing, #93005 - -2002-09-29 Havoc Pennington <hp@pobox.com> - - * src/effects.h (META_MINIMIZE_ANIMATION_LENGTH): shorten minimize - animation a bit - -2002-09-28 Havoc Pennington <hp@pobox.com> - - Patch from Keith Packard to handle root window resizes. - - * src/screen.c (reload_xinerama_infos): factor out Xinerama code - (meta_screen_resize): implement this, to be called from display.c - on screen resize - - * src/display.c (event_callback): handle ConfigureNotify on root - windows - -2002-09-28 Havoc Pennington <hp@pobox.com> - - * src/stack.c (get_standalone_layer): re-enable the FOCUSED_WINDOW - layer, should now work correctly. - -2002-09-28 Havoc Pennington <hp@pobox.com> - - * src/window.c, src/stack.c: Rewrite stack code to work a lot - differently. Should be better now, and not lose relative positions - of windows when moving among layers. Also should now be possible - to get session management to restore the stacking order. Probably - breaks some stuff, and makes all the stack.c changes I made - yesterday sort of irrelevant. - -2002-09-27 Havoc Pennington <hp@pobox.com> - - * src/stack.c (get_standalone_layer): Temporarily disable use of - the FOCUSED_WINDOW layer, because given the fact that moving - multiple windows into the same layer changes the Z-order of those - windows, it was breaking click-to-focus. - -2002-09-27 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_focus_top_window): raise the focused - window, since it may not be the window on top, given the below - change. - - * src/stack.c (meta_stack_get_default_focus_window): make this - more complex to prefer to focus the transient parent, followed by - other windows in group, followed by topmost non-dock, followed by - dock. Previously was just topmost non-dock followed by dock - ignoring groups and transiency. - -2002-09-27 Havoc Pennington <hp@pobox.com> - - * src/place.c (constrain_placement): constrain placement to try to - keep windows from going offscreen to the right/bottom - - * src/stack.c (compute_layer): rearrange the logic here to say - that a window must always be in at least as high a layer as any of - its transient parents or group members, rather than special-casing - fullscreen. Also, group_member_is_fullscreen was leaking the list - of group members every time, a fairly major memory leak. - -2002-09-27 Havoc Pennington <hp@redhat.com> - - * src/themes/Makefile.am (THEMES): use AgingGorilla not Gorilla - (renamed on the CVS server) - -2002-09-27 Havoc Pennington <hp@redhat.com> - - Try to handle Solaris Xinerama, all coded blind, someone - on Solaris will need to debug the typos. - - * src/display.c: updates for Solaris Xinerama - - * src/screen.c: updates for Solaris Xinerama - - * configure.in: make Xinerama check more complicated to catch - Solaris Xinerama - -2002-09-27 Havoc Pennington <hp@redhat.com> - - * src/window.c (update_transient_for): keep a flag - transient_parent_is_root_window for whether the - root-window-as-parent convention was used. - -2002-09-25 Arvind Samptur <arvind.samptur@wipro.com> - - * src/stack.c (sort_window_list): Keep dialogs without - transient parent above entire app. Fixes #88926 - -2002-09-26 Havoc Pennington <hp@pobox.com> - - * src/menu.c (meta_window_menu_new): use MetaAccelLabel to display - accelerators for the menu items - - * src/metaaccellabel.c: cut-and-paste GtkAccelLabel and port to - use virtual modifiers - - * src/Makefile.am (metacity_SOURCES): add metaaccellabel.[hc] - - * src/prefs.c (meta_prefs_get_window_binding): new function - - * src/core.c (meta_core_get_menu_accelerator): new function - -2002-09-25 Havoc Pennington <hp@redhat.com> - - * src/metacity.schemas.in: Change short desc of switch_windows and - cycle_windows to be different - -2002-09-24 Havoc Pennington <hp@pobox.com> - - * src/place.c (fit_rect_in_xinerama): update best_overlap as we go - through the loop - doh. Fix from readams@hmc.edu for #90799. - (find_first_fit): try the origin of each xinerama screen - after the first. Also from readams@hmc.edu - -2002-09-24 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_save_rect): new function, - only saves rect after checking current state, #93795 - (meta_window_make_fullscreen): use new function - (meta_window_maximize): use new function - -2002-09-24 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_update_layer): new function - - * src/stack.c (compute_layer): put focused window in a layer above - all other windows, in click-to-focus mode. #93022 - - * src/window.c (meta_window_notify_focus): update window layer on - focus change. - -2002-09-24 Havoc Pennington <hp@redhat.com> - - * src/main.c (main): support --version, #92796 patch from - Christian Neumair - - * autogen.sh: change gettext test to be happy with - glib-gettextize, #81425 - - * src/menu.c: change mnemonics to match bug #78999 - - * src/theme.c (meta_theme_validate): consolidate some - nearly-identical themes for ease of translation, #70962 - -2002-09-24 Arvind Samptur <arvind.samptur@wipro.com> - - * src/menu.c: Replace strings Shade with Roll Up and - Unshade with Unroll. - -2002-09-23 Havoc Pennington <hp@pobox.com> - - * src/main.c (main): re-enable the log handler, maybe it will - break something, I don't remember why I turned it off. - - * src/display.c: s/_NET_SHOW_DESKTOP/_NET_SHOWING_DESKTOP/ which - is what's in the spec - -2002-09-22 Havoc Pennington <hp@pobox.com> - - * src/window.c (recalc_window_features): small reordering of - code - - * src/display.c (meta_spew_event): more spew for MapNotify, - UnmapNotify - - * src/window.c (recalc_window_features): spew more stuff - - * src/display.c (meta_spew_event): spew override_redirect field of - ConfigureNotify - -2002-09-20 Arvind Samptur <arvind.samputr@wipro.com> - * src/metacity.schemas.in: added keybindings for - moving windows between workspaces. - - Patch from Jeyasudha. Fixes #91944. - -2002-09-19 Arvind Samptur <arvind.samptur@wipro.com> - * src/tools/metacity-properties.desktop.in : - change in the tooltip suggested in ui-review. - -2002-09-18 Havoc Pennington <hp@redhat.com> - - * src/window.c (update_net_wm_state): handle fullscreen state - here. - -2002-09-15 Havoc Pennington <hp@pobox.com> - - * src/session.c (save_state): escape the window title before - saving in the session file, reported by Jos Vos - -2002-09-12 Havoc Pennington <hp@redhat.com> - - * src/workspace.c (meta_workspace_screen_index) - (meta_workspace_index): fix compiler warnings - - * src/tools/metacity-window-demo.c (menu_items): add a test for - dialogs with no transient parent - - * src/place.c (find_first_fit): Try placing window at origin of - first Xinerama, even if there are no windows to place next to; - makes placement work when no other windows are open on the screen. - -2002-09-09 Havoc Pennington <hp@pobox.com> - - * configure.in: 2.4.1 - -2002-09-09 Christian Neumair <chris@gnome-de.org> - - * src/keybindings.c: Make virtual desktops apply - instantly and still show the pager popup by - Benjamin Kahn <xkahn@zoned.net>, fixes #86590. - -2002-09-06 Frederic Crozat <fred@crozat.net> - - * src/themes/Crux/metacity-theme-1.xml: Fix titlebar - glitch on small dialogs. - -2002-09-06 Arvind Samptur <arvind.samptur@wipro.com> - * theme-format.txt : corrected some of the attributes - which were not in sync with theme-parser.c - Patch from Jim Bowen. #92057. - -2002-09-05 Havoc Pennington <hp@pobox.com> - - * configure.in: put ro back in ALL_LINGUAS - -2002-09-05 Havoc Pennington <hp@redhat.com> - - * configure.in (ALL_LINGUAS): remove 'ro' from ALL_LINGUAS, it - contained invalid XML and broke the build. No <> in the - translations of gconf keys! - -2002-09-04 Marius Andreiana <mandreiana@yahoo.com> - - * configure.in: added 'ro' to ALL_LINGUAS - -2002-09-03 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_get_tab_current): new function - - * src/keybindings.c (do_choose_window): apply modified patch from - JeyaSudha to still display tab popup if only one window is on the - desktop. - -2002-06-25 JeyaSudha <jeyasudha.duraipandy@wipro.com> - - * src/session.c, src/window.c: Session saves the unmaximized - postion, size of a maximized window. #86059 - -2002-09-03 Havoc Pennington <hp@pobox.com> - - * src/frames.c (meta_frames_update_prelit_control): don't filter - out prelight for unmaximize button. #83860 - (meta_frames_paint_to_drawable): handle unmaximize here as well - -2002-08-27 Havoc Pennington <hp@pobox.com> - - * src/theme.c (meta_frame_layout_calc_geometry): always apply - rounding for shaded windows, fixes Bluecurve theme when shaded - -2002-08-25 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_free): when freeing a fullscreen - window, update layers of the window's group. - -2002-08-25 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_open): _NET_SUPPORTING_WM_CHECK is - supposed to have type WINDOW not CARDINAL. reported by - Ben Jansens - -2002-08-24 Havoc Pennington <hp@redhat.com> - - * src/window.c (process_property_notify): recalculate mapped-ness - of frame after toggling decorations on/off, so that windows don't - disappear when decorations are toggled on. - - * src/tools/metacity-window-demo.c (toggle_decorated_cb): add a - test for toggling decoration state on the fly - -2002-08-24 Havoc Pennington <hp@redhat.com> - - * src/window.c (update_sm_hints): hack around bug in kmail etc. - where SM_CLIENT_ID was set on the window, not the client leader. - - * src/theme.c (meta_frame_layout_calc_geometry): don't round - corners unless we have enough frame to chop off. - -2002-08-24 Havoc Pennington <hp@redhat.com> - - * src/util.c: translate some strings that should have been, and - convert to locale encoding before printing stuff. - - * src/stack.c (group_member_is_fullscreen): if window itself is - fullscreen, return TRUE immediately. - - * src/window.c (meta_window_configure_request): add hack to - fullscreenize large undecorated windows. - -2002-08-21 Deepa Natarajan <deepa.natarajan@wipro.com> - - * src/keybindings.c, src/metacity.schemas.in, src/prefs.[ch]: - add maximize and unmaximize keybinding setting. Partly fixes - bug# 78999. - -2002-08-20 Steve Fox <drfickle@k-lug.org> - - * metacity.spec.in: Add so that the spec file gets auto-updated - whenever configure.in gets bumped. Include some missing - directories. - - * Makefile.am - * configure.in: Necessary changes for spec file magic - -2002-08-20 Havoc Pennington <hp@redhat.com> - - * src/frames.c (get_control): if in the title rect check for y - <= TOP_RESIZE_HEIGHT - - * src/display.c (meta_spew_event): put x/y coordinates in spew for - enter/leave notify - - * src/frames.c (meta_frames_motion_notify_event): move cursor - changing from here to update_prelit_control so it happens on enter - notify as well - (get_control): change test "y < TOP_RESIZE_HEIGHT" to - "y <= TOP_RESIZE_HEIGHT" - - * src/Makefile.am (EXTRA_DIST): include .in files in EXTRA_DIST - -2002-08-17 Simos Xenitellis <simos@hellug.gr> - - * configure.in (ALL_LINGUAS): Added Greek (el). - -2002-08-17 Evandro Fernandes Giovanini <evandrofg@ig.com.br> - - * configure.in (ALL_LINGUAS): Added Brazilian Portuguese (pt_BR). - -2002-08-15 Havoc Pennington <hp@redhat.com> - - * src/metacity.schemas.in: default to "Sans Bold 10" for the - titlebar font. - -2002-08-15 Havoc Pennington <hp@pobox.com> - - * src/window.c (recalc_window_features): leave has_fullscreen_func - set to TRUE if the window is screen sized and undecorated, even if - the window isn't resizable. idea from Christian - Manny Calavera - - Neumair - - * src/keybindings.c (handle_toggle_fullscreen) - (handle_toggle_maximize): these disabled fullscreen/maximize if - the window wasn't resizable, should have used has_fullscreen_func - has_maximize_func instead. - -2002-08-15 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c: implement raise/lower - - * src/metacity.schemas.in: add raise/lower - - * src/prefs.c: add "raise" and "lower" prefs to keybindings - - * src/display.c (meta_display_set_grab_op_cursor): assert that - the screen arg is non-NULL in appropriate cases - -2002-08-14 Jayaraj Rajappan <jayaraj.rajappan@wipro.com> - - * src/display.c (meta_display_set_grab_op_cursor): - In XGrabPointer, set the confine_to argument to the root window - of the screen the window is on. - - * src/display.h: add screen argument. - - * src/window.c (meta_window_update_resize_grab_op): - pass screen argument as NULL. - -2002-08-14 James M. Cape <jcape@ignore-your.tv> - - * src/themes/Esco/metacity-theme-1.xml: use button positioning - theme stuff. - -2002-08-14 Mark McLoughlin <mark@skynet.ie> - - * src/screen.c: (set_number_of_spaces_hint), move from - workspace.c. - (update_num_workspaces): set the hint here. Fixes #90123. - - * src/workspace.c: - (meta_workspace_new), (meta_workspace_free): don't set - the hint here. - (update_num_workspaces): move to screen.c - -2002-08-12 Havoc Pennington <hp@redhat.com> - - * src/stack.c (compute_layer): window is in fullscreen layer if - any member of its group is fullscreen - - * src/window.c (meta_window_unmake_fullscreen): update layer for - whole window group - (meta_window_make_fullscreen): ditto - - * src/util.c (meta_unsigned_long_hash): move hash/equal funcs for - Window in here. - - * src/group.c: track window groups so we can do stuff with them. - -2002-08-11 Havoc Pennington <hp@pobox.com> - - * src/menu.c: don't include nonexistent stock-icons.h file - -2002-08-10 Havoc Pennington <hp@pobox.com> - - * src/metacity.schemas.in: default keybindings for move, resize, - maximize, etc. from Deepa #78999 - -2002-08-10 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_maximize): unshade window if shaded, - from JeyaSudha - (meta_window_make_fullscreen): ditto - -2002-08-10 Havoc Pennington <hp@pobox.com> - - * src/menu.c: reorder the menu items so that Close is at the - bottom - - * src/theme-viewer.c (main): set debugging mode if METACITY_DEBUG - enabled - -2002-08-10 Havoc Pennington <hp@pobox.com> - - * src/xprops.c (meta_prop_get_motif_hints): allow Motif hints to - be smaller than expected; GLUT for example seems to set a smaller - struct. #89841 - - * src/window.c (update_mwm_hints): use g_free on motif hints as we - don't use the XGetWindowProperty return directly anymore - -2002-08-10 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_free): be sure window is - mapped if we unmanage it and it's not withdrawn; - bug #90369 - - * src/screen.c (meta_screen_new): change string - s/override/replace/ bug #89077 - - * src/theme.c (scale_and_alpha_pixbuf): dump the - sometimes-use-NEAREST-instead-of-BILINEAR optimization, - bug #87489 - -2002-08-10 Havoc Pennington <hp@pobox.com> - - * src/window.c (menu_callback): raise window when moving to - another workspace bug #88896 - - * src/keybindings.c (switch_to_workspace): raise window when - moving between spaces - -2002-08-10 Jorn Baayen <jorn@nl.linux.org> - - Register window menu icons with the Gtk stock system, instead - of using the ones from the Metacity theme (which looked very bad with - some themes). - - * src/Makefile.am: - * src/main.c: - * src/menu.c: - * src/stock_delete.png: added these files - * src/stock_minimize.png: - * src/stock_maximize.png: - * src/ui.c - -2002-08-10 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (meta_display_process_key_event): filter out - key events that happen on popup menus etc. - - * src/ui.c (meta_ui_window_is_widget): new function to check - whether a window belongs to a GtkWidget such as the popup menu - - * src/prefs.c (change_notify): put in a no-op line for AIX - compiler, #84252 - -2002-08-10 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_resize): track time to avoid sending a - deluge of move/resize requests, suggestion from - xavier.bestel@free.fr bug #86830. Not really sure if this will - make a difference or not. We'll see I guess. - (update_move): do same on move though it seems less important - here. - - * src/display.h (struct _MetaDisplay): store the - last time we sent a move/resize event. - -2002-08-10 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_notify_focus): add a FIXME comment - with a link to bug #90382 - -2002-08-09 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (handle_toggle_maximize): disable maximize, - fullscreen, shade via keybindings on windows that don't support - it. - -2002-08-08 Craig Black <blackc@speakeasy.net> - - Patch to provide extra cues when using the window menu - move and resize items, #85724. - - * src/common.h: add new cursors - - * src/display.c: (grab_op_is_mouse) - (meta_display_create_x_cursor), (xcursor_for_op), - (meta_display_set_grab_op_cursor), - (meta_display_begin_grab_op): - The keyboard move and resize grab ops now also use the mouse. - Allow the grab cursor to be changed during the grab op. - Hold onto the initial grab position in case of reset. - - * src/display.h: save the initial grab position - - * src/keybindings.c: (process_keyboard_move_grab), - (process_keyboard_resize_grab), (handle_begin_move), - (handle_begin_resize): - The keyboard move and resize grab ops now also use the mouse. - - * src/window.c: (meta_window_client_message), (menu_callback), - (update_move), (update_resize), - (meta_window_handle_mouse_grab_op_event), (warp_pointer), - (meta_window_warp_pointer), (meta_window_begin_grab_op), - (meta_window_update_resize_grab_op): - When moving or resizing a window use the last grab position - in computing change increment. - Provide support for warping the mouse pointer. - - * src/window.h: new warp pointer and grab op helper functions - -2002-08-08 Craig Black <blackc@speakeasy.net> - - * src/display.h: update comment - * src/window.c: (meta_window_focus): also set expected - focus window when setting input focus. - -2002-08-07 Craig Black <blackc@speakeasy.net> - - * src/display.c: (meta_display_unshow_desktop): focus - top window after showing desktop, fixes #88080. - -2002-08-07 Craig Black <blackc@speakeasy.net> - - * src/core.c: (meta_core_show_window_menu): focus window - on right click for menu, #87299. - -2002-08-07 Craig Black <blackc@speakeasy.net> - - * src/display.c: (meta_display_open): clear expected focus window - on open - - * src/display.h: add expected_focus_window field - - * src/window.c: (meta_window_make_fullscreen), - (meta_window_unmake_fullscreen): change meta_window_update_layer() - to meta_stack_update_layer() so build works again. - (meta_window_free), (meta_window_make_fullscreen), - (meta_window_focus), (meta_window_notify_focus): keep track of - expected focus window after sending WM_TAKE_FOCUS event, - previously if a UnmapNotify event arrived before the FocusIn event - we would lose focus, fixes #84564. - -2002-08-07 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_unmake_fullscreen): update layer - (meta_window_make_fullscreen): update layer - - * src/stack.c (compute_layer): put window on fullscreen layer if - fullscreen - -2002-08-06 Craig Black <blackc@speakeasy.net> - - * src/window.c: (meta_window_client_message): implement - _NET_WM_MOVERESIZE enhancements, see #90077. - -2002-08-06 Havoc Pennington <hp@redhat.com> - - * configure.in: 2.4.0 (this version number has no special - significance, just didn't want to go to 4-digit micro version ;-) - -2002-07-28 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_shade): disable animation when shading - windows, just doesn't really convey the idea anyway. - - * src/effects.c: Move to using a shaped window instead of - IncludeInferiors to do the animations, looks a lot better - because we don't have to grab the server. - - * src/window.c (meta_window_change_workspace): remove bogus - assertion that was causing a crash - (meta_window_new): auto-fullscreen huge undecorated windows. - - * src/keybindings.c (switch_to_workspace): use - meta_window_change_workspace() to avoid same bug in cut-and-paste - code from there - -2002-08-06 He Qiangqiang <carton@linux.net.cn> - - * configure.in: Added "zh_CN" to ALL_LINGUAS. - -2002-08-05 Ross Burton <ross@burtonini.com> - - * src/window.c: (meta_window_client_message): Set - ->wm_state_skip_pager (ditto for _taskbar) instead of ->skip_pager - so that these hints actually work. Fixes #89850. - -2002-08-04 Havoc Pennington <hp@redhat.com> - - * src/frames.c (meta_frames_paint_to_drawable): init button - states for the button backgrounds - - * src/themes/Atlanta/metacity-theme-1.xml: adapt to work correctly - with button repositioning - -2002-08-04 Havoc Pennington <hp@redhat.com> - - * src/frames.c (meta_frames_button_press_event): raise/focus - on click, even if the click was on the client area - (this makes Alt+button1 raise windows again, yay) - - * src/stack.c (compute_layer): put panels in the DOCK layer always - (keep them on top of other windows). Still sloppy-focus raised - with respect to other docks. - - * configure.in: remove -Wshadow for now as GTK headers make all - kinds of noise with it. - -2002-08-02 Mark McLoughlin <mark@skynet.ie> - - * src/screen.c: (meta_screen_new): set active_workspace - to NULL. Also actually activate the first workspace instead - of just setting active_workspace. Fixes #87367. - (meta_screen_ensure_workspace_popup): don't re-use our - iterator for setting the entries list, stop iterating - when we've gone beyond the last workspace (there may - be empty spaces in the last row). - - * src/workspace.c: (meta_workspace_activate): if no workspace - was previously activated, return. - -2002-08-04 Havoc Pennington <hp@redhat.com> - - * src/theme.c (free_menu_ops): use MetaMenuIconType not button - type for the size of the menu ops array - (meta_theme_define_int_constant): return TRUE on success (how the - heck did this ever work?) - (meta_theme_define_float_constant): return TRUE on success - (meta_frame_style_validate): allow the "positional" buttons to - be omitted for now. - - * src/testgradient.c (render_multi): don't define N_COLORS twice - - * src/theme-viewer.c (run_theme_benchmark): don't define - ITERATIONS twice - - * src/theme.c (button_rect): handle new button types - (meta_button_type_to_string): update - (meta_button_type_from_string): update - - * src/theme.h (enum): add button types for the 6 possible button - positions. No way to reposition buttons still but this will allow - themes to go ahead and support doing so. - -2002-08-03 Craig Black <blackc@speakeasy.net> - - * src/keybindings.c: (meta_display_process_key_event), - (process_tab_grab), (do_choose_window): change alt+tab to a - windowless grab, fixes #83499 - -2002-08-03 Craig Black <blackc@speakeasy.net> - - * src/display.c: (event_callback): Have ButtonPress and - UnmapNotify events account for a null grab window, fixes #87896 - -2002-08-03 Gaute Lindkvist <lindkvis@linpro.no> - - Corrected some issues with the Bright theme. Mainly - making sure the text does not clip, as well as increasing - the size of the menu icon. - -2002-08-01 Mark McLoughlin <mark@skynet.ie> - - Implements support for _NET_WM_ALLOWED_ACTIONS. - Fixes #84282. - - * src/display.[ch]: (meta_display_open): add - _NET_WM_ALLOWED_ACTIONS atoms. - - * src/screen.c: (set_supported_hint): set them - as being supported. - - * src/window.c: - (set_allowed_actions_hint): impl setting - _NET_WM_ALLOWED_ACTIONS. - (recalc_window_features): use it here, but only - if things have changed. - -2002-08-01 Christophe Fergeau <teuf@users.sourceforge.net> - - * src/metacity-dialog.c: focus the "Close" button by default on - the dialog which appears at exit when some apps can't be session - managed - -2002-08-01 Mark McLoughlin <mark@skynet.ie> - - * src/session.c: - (save_yourself_possibly_done): send a SaveYourselfDone - if we're skipping this global save. - (save_yourself_callback): don't not save session state - if the save style is Global. Fixes #89390. - - * theme-format.txt: update. - -2002-07-30 Pablo Saratxaga <pablo@mandrakesoft.com> - - * configure.in: Added Vietnamese (vi) to ALL_LINGUAS - -2002-07-24 Havoc Pennington <hp@pobox.com> - - * src/themes/Makefile.am (THEMES): add Metabox theme from Garrett - - * README: updates - -2002-07-21 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_new): don't automaximize fullscreen - windows. - -2002-07-14 Havoc Pennington <hp@pobox.com> - - * src/window.c (recalc_window_features): don't allow shading of - border-only windows. - -2002-07-24 Havoc Pennington <hp@redhat.com> - - * src/theme-parser.c (meta_theme_load): look for themes in - ~/.themes/NAME/metacity-1/ and datadir/themes/NAME/metacity-1 - instead of the old locations. - - * src/themes/Makefile.am: install themes to - datadir/themes/NAME/metacity-1/ to match how GTK works, breaking - third-party themes yet again! woot! - -2002-07-20 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_open): grab display across managing - each screen; XGetInputFocus() on startup. - -2002-07-19 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_configure_request): disable configure - requests during a user move/resize operation, mostly a workaround - for stoopid apps. - -2002-07-24 jacob berkman <jacob@ximian.com> - - * configure.in: fix x11 header checks when x11 is not in the - default include path - -2002-07-23 Ross Burton <ross@burtonini.com> - - * src/menu.c (meta_window_menu_new): Use the real workspace names - instead of making up numbers. - -2002-07-23 Havoc Pennington <hp@redhat.com> - - * src/themes/Makefile.am (THEMES): put Gorilla back in the build - - * src/themes/Gorilla/metacity-theme-1.xml, - src/themes/Crux/metacity-theme-1.xml: fixes from - Sebastien Delestaing so that these themes work properly with - different font sizes. - - * src/frames.c (get_control): patch from Balamurali Viswanathan - for #81984 (resize titlebar from the top not the bottom) - -2002-07-23 Havoc Pennington <hp@redhat.com> - - * src/keybindings.c (meta_display_process_key_event): handle - NULL screen from screen_for_xwindow - - * src/display.c (meta_display_screen_for_xwindow): put an error - trap around the XGetWindowAttributes(), should fix the popular - "closing a window results in a crash" bug. - - * src/util.c (print_backtrace): support optional backtrace - feature using gnu libc backtrace() call - -2002-07-15 jacob berkman <jacob@ximian.com> - - * src/update-from-egg.sh: steal from profterm to fix build - -2002-07-13 Havoc Pennington <hp@pobox.com> - - * src/workspace.c (meta_workspace_new): don't put a newline after - the default workspace name - -2002-07-13 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c: adapt to virtual modifiers - (meta_display_process_mapping_event): we need to reload the - binding tables now when the modmap changes. - - * src/prefs.c (update_binding): parse virtual modifiers, not - plain modmask - - * src/common.h (MetaVirtualModifer): new enum - - * src/ui.c (meta_ui_parse_accelerator): use - egg_accelerator_parse_virtual() - - * src/Makefile.am: add eggaccelerators.[hc] for the virtual - accelerator parsing function - -2002-07-13 Christophe Fergeau <teuf@users.sourceforge.net> - - * configure.in: added fr to ALL_LINGUAS - -2002-07-12 Havoc Pennington <hp@pobox.com> - - * src/session.c (warn_about_lame_clients_and_finish_interact): - don't display the dialog if all the apps were session managed. - -2002-07-12 Havoc Pennington <hp@pobox.com> - - * src/session.c: don't send SmInteractDone until the warning - dialog about crappy clients has been closed. - -2002-07-12 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_new): try to maximize windows that - are too big for the work area - - * src/place.c (find_next_cascade): don't let the cascade algorithm - place windows off the screen, and fix it to always exhaustively - search the window list for cascade parents. - -2002-07-11 Havoc Pennington <hp@pobox.com> - - * src/metacity-dialog.c (main): option to display error when a - command fails to run. - - * src/keybindings.c (handle_run_command): run commands - in response to keybindings. - - * src/prefs.c: add command keybinding stuff - - * src/metacity.schemas.in: add keybindings for running commands, - and keys to store the commands themselves. - -2002-07-10 Havoc Pennington <hp@redhat.com> - - * src/display.c: properly attribute selection code to Matthias - Clasen - -2002-07-10 Havoc Pennington <hp@pobox.com> - - * README: couple of updates - - * src/main.c (usage): add --replace to usage, reported by Matthias - Clasen - -2002-07-09 Havoc Pennington <hp@pobox.com> - - * src/metacity.schemas.in: fix short description for - begin_resize, patch from Jayaraj, #87654 - - * src/keybindings.c (handle_begin_resize): apply patch from - Jayaraj to actually handle the begin resize keybinding. - -2002-07-09 Havoc Pennington <hp@pobox.com> - - * src/window.c (constrain_position): don't center vertically for - maximized windows that don't fill the screen, just leave them at - the top. - -2002-07-06 Havoc Pennington <hp@pobox.com> - - * src/tabpopup.c (selectable_workspace_new): increase the size of - the mini workspaces - -2002-07-06 Havoc Pennington <hp@pobox.com> - - Apply blackc@speakeasy.net patch, bug #83940, to do - mini-workspaces similar to the pager, when switching - spaces. - - * src/window.c (update_net_wm_state): actually fill in - wm_state_skip_taskbar, wm_state_skip_pager flags - - * src/tabpopup.c: support drawing a mini-workspace similar to the - one the pager draws. - - * src/stack.c (meta_stack_list_windows): new function to list - the windows in stacking order - - * src/screen.c (meta_screen_ensure_workspace_popup): don't pass in - the ugly default app icon for workspaces - - * src/display.c (event_callback): fix from blackc@speakeasy.net - to avoid dereferencing a NULL grab window. - -2002-07-06 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_open): put _NET_DESKTOP_NAMES in the - array of atom names, so desktop names might work and we don't read - uninitialized memory. - - * src/main.c (main): add VERSION/timestamp verbose message. - - * src/keybindings.c: implement cycle_windows cycle_panels - - * src/metacity.schemas.in: add the cycle_windows cycle_panels - keybindings - - * src/prefs.h (META_KEYBINDING_FOCUS_PREVIOUS): replace - FOCUS_PREVIOUS key binding with CYCLE_WINDOWS and CYCLE_PANELS - (not good names really, but I don't have ideas). - - * src/common.h: add a grab op for alt+esc window cycling - -2002-07-05 Havoc Pennington <hp@pobox.com> - - * src/themes/Makefile.am (THEMES): Take Gorilla out until it gets - repaired. - -2002-07-05 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_wm_hints): Change default value of input - hint (if not specified) to true instead of false. This is what - some clients assume, such as Visual SlickEdit. - -2002-07-02 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_show_menu): use new macros to get - whether we allow move/resize correct - - * src/frame.c (meta_frame_get_flags): use new macros to get - whether we can move/resize correct, considering - maximized/fullscreen for the move case. - - * src/window.h (META_WINDOW_ALLOWS_RESIZE, - META_WINDOW_ALLOWS_MOVE): new macros - - * src/keybindings.c (process_keyboard_resize_grab): finish the - right/left resize, patch from Jayaraj #78179. - - Has the same old move/resize bug, if it hits a constraint it - starts to break because we move without resizing. - -2002-07-02 Mark McLoughlin <mark@skynet.ie> - - * src/keybindings.c: - (grab_keyboard), (ungrab_keyboard): rename from - {un}grab_all_keys_and_keyboard and only do an XKeyboardGrab, - the XKeyGrab isn't neccessary. - (meta_screen_grab_all_keys), (meta_screen_ungrab_all_keys), - (meta_window_grab_all_keys), (meta_window_ungrab_all_keys): - update for above change. - (handle_workspace_switch): don't use a MetaWindow when - workspace switching, use the root window instead. - -2002-07-01 Mark McLoughlin <mark@skynet.ie> - - Fix broken workspace switching from my previous commit. - - * src/display.c: (meta_display_begin_grab_op): don't - leak a pointer grab if we fail to grab the keyboard. - - * src/keybindings.c: (meta_screen_grab_keys): check - screen->all_keys_grabbed. - (meta_screen_grab_all_keys): regrab our standard - bindings if we fail. - (handle_workspace_switch): revert to our previous - behaviour of using the last focused window to do - the grab upon. Only use the RootWindow if there - isn't anything else to use. - - * src/screen.c: (meta_screen_new): initialise - all_keys_grabbed. - -2002-06-26 Mark McLoughlin <mark@skynet.ie> - - Fixes not being able to tab out of a - workspace which contains no windows. - - * src/core.c: (meta_core_begin_grab_op): upd - for meta_display_begin_grab_op change. - (meta_core_get_grab_frame): allow for - grab_window == NULL. - - * src/display.[ch]: - (meta_display_screen_for_xwindow): implement. - (meta_display_begin_grab_op): grab on the root window - if window == NULL. - (meta_display_end_grab_op): use grab_screen instead of - grab_window. - - * src/keybindings.c: - (grab_all_keys_and_keyboard): split out from - meta_window_grab_all_keys. - (ungrab_all_keys_and_keyboard): split out from - meta_window_ungrab_all_keys. - (meta_screen_grab_all_keys), (meta_screen_ungrab_all_keys): - implement grabbing and ungrabbing on the root window. - (meta_display_process_key_event): if window == NULL, - check the event is from the same screen and process. Only - happens with workspace switching. - (process_workspace_switch_grab): kill window param and - don't use grab_window. - (handle_tab_forward), (handle_begin_move): upd for - meta_display_begin_grab_op change. - (handle_workspace_switch): remove brokeness. Always do - the grab op on the root window. - - * src/keybindings.h: add meta_screen_{un}grab_all_keys. - - * src/window.c: (meta_window_client_message), (menu_callback): - update for meta_display_begin_grab_op change. - -2002-06-25 Mark McLoughlin <mark@skynet.ie> - - * src/fixedtip.c: (meta_fixed_tip_show): - * src/frames.c: (meta_frames_new): - * src/tabpopup.c: (meta_ui_tab_popup_new): - s/gdk_get_default_display/gdk_display_get_default/ - s/gdk_get_default_screen/gdk_screen_get_default/ - -2002-06-25 Mark McLoughlin <mark@skynet.ie> - - * src/themes/Crux/active-border-top-left-border.png: - * src/themes/Crux/active-border-top-right-border.png: - * src/themes/Crux/active-top-left-corner.png: - * src/themes/Crux/active-top-mid-left-border.png: - * src/themes/Crux/active-top-mid-right-border.png: - * src/themes/Crux/active-top-right-corner.png: - * src/themes/Crux/inactive-border-top-left-border.png: - * src/themes/Crux/inactive-border-top-right-border.png: - * src/themes/Crux/inactive-top-left-corner.png: - * src/themes/Crux/inactive-top-mid-border.png: - * src/themes/Crux/inactive-top-right-corner.png: - * src/themes/Crux/metacity-theme-1.xml: added support - for border only windows. - -2002-06-24 James M. Cape <jcape@ignore-your.tv> - - * src/themes/Esco/metacity-theme-1.xml: Added some stuff to - the window buttons, so they use the ACTIVE bg/fg. - -2002-06-25 Mark McLoughlin <mark@skynet.ie> - - * src/display.[ch]: (meta_display_open): - src/screen.c: (set_supported_hint), (set_work_area_hint): - Its _NET_WORKAREA, not _NET_WM_WORKAREA silly :-) - -2002-06-25 Mark McLoughlin <mark@skynet.ie> - - * src/screen.[ch]: - (update_num_workspaces), recalc workarea hint when - new workspaces created. Fixes bug that workarea - not calculated until first non-dock window is - mapped. - (set_work_area_hint), (set_work_area_idle_func), - (meta_screen_queue_workarea_recalc): move all this - stuff from workspace.c. - - * src/workspace.c: (meta_workspace_invalidate_work_area): - use meta_screen_queue_workarea_recalc. - -2002-06-23 Gediminas Paulauskas <menesis@delfi.lt> - - * src/themes/Bright/metacity-theme-1.xml: Update with border-only - window stuff from Atlanta. - -2002-06-22 James M. Cape <jcape@ignore-your.tv> - - * src/themes/Esco/metacity-theme-1.xml: Update for "border" - frame stuff, minor button/spacing improvements. - -2002-06-22 Havoc Pennington <hp@pobox.com> - - Partially fix Jacob's SM bugs. - - * src/window.c (meta_window_apply_session_info): restore the extra - stuff we're saving, except stack position I didn't figure out yet. - - * src/session.c: save stack position, minimized, maximized, - in the session file. - -2002-06-22 Havoc Pennington <hp@pobox.com> - - * src/workspace.c (set_number_of_spaces_hint): do nothing if - screen is being unmanaged, we don't want to blow away state, - we want to remember it for the next window manager. - -2002-06-22 Havoc Pennington <hp@pobox.com> - - * src/workspace.c (meta_screen_ensure_workspace_popup): rename - from meta_workspace_ensure_tab_popup, and use workspace->name - instead of a hardcoded name - -2002-06-22 Havoc Pennington <hp@pobox.com> - - * src/xprops.c (meta_prop_get_utf8_list): new utility function - - * src/display.c (meta_display_open): _NET_DESKTOP_NAMES atom - (event_callback): update workspace names when the property changes - - * src/screen.c (set_supported_hint): "support" _NET_DESKTOP_NAMES - (nothing to do really) - -2002-06-21 Havoc Pennington <hp@pobox.com> - - Theme breakage! Themes have to implement "border" frames - now, see Atlanta for an example. Fixes #84285 - - * src/tools/metacity-window-demo.c (do_appwindow): add a - border-only window - - * src/window.c (update_mwm_hints): read border only from the MWM - hints - - * src/window.h (struct _MetaWindow): add border_only flag - - * src/core.c (meta_core_get_frame_type): report border type if - required - - * src/common.h (enum): add META_FRAME_TYPE_BORDER - -2002-06-20 Mark McLoughlin <mark@skynet.ie> - - * src/window.c: (meta_window_visible_on_workspace): sticky - windows aren't visibile on all screens. Check the workspace - is on the same screen as the window. - - * src/workspace.c: (meta_workspace_list_windows): use - meta_window_visible_on_workspace here. - -2002-06-19 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_resize_gravity_from_grab_op): handle UNKNOWN - keyboard resizing state - - * src/keybindings.c (process_keyboard_resize_grab): implement - keyboard resize key handling somewhat (only vertical resize works, - left/right arrow not implemented, and visual feedback of the - edge we're resizing isn't implemented) - - * src/window.c (menu_callback): start keyboard resize grab when - it's chosen from the menu - -2002-06-17 Havoc Pennington <hp@pobox.com> - - * src/stack.c (meta_stack_get_default_focus_window): don't use a - minimized window as the next focus window, patch from - blackc@speakeasy.net - -2002-06-17 Havoc Pennington <hp@pobox.com> - - * src/place.c (find_next_cascade): increase the cascade threshold - a bit. - (find_first_fit): implement a somewhat lame first fit algorithm - -2002-06-17 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_change_workspace): fix from Gaute - Lindkvist #82977 for unsticking windows - -2002-06-17 Frederic Crozat <fcrozat@mandrakesoft.com> - - * src/metacity.schemas.in: associate close_window keybinding to - Alt-F4 - -2002-06-16 Havoc Pennington <hp@pobox.com> - - * src/main.c (main): fix spelling error, #85452 - -2002-06-15 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (meta_display_process_key_event): don't pass a - null string to printf - - * src/display.c (key_event_description): don't pass a null string - to printf - - * src/keybindings.c (meta_set_keybindings_disabled): allow - enable/disable keybindings regardless of debug mode. - -2002-06-15 Havoc Pennington <hp@pobox.com> - - * src/draw-workspace.h, src/draw-workspace.c: workspace-drawing - code factored out of libwnck, needs wiring up to tabpopup.c - (which is kind of annoying since you have to get the list of - workspaces and MetaWindow across the barrier between the GDK-aware - and non-GDK-aware sides of metacity) - -2002-06-14 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_show): always focus new windows, - trying to be smart about it was a flop. - -2002-06-14 Jayaraj Rajappan <jayaraj.rajappan@wipro.com> - - * src/delete.c (io_from_ping_dialog): Check for NULL string - before calling strlen(). Fixes the core dump issue reported in #84873. - -2002-06-13 Anders Carlsson <andersca@gnu.org> - - * src/theme.c (meta_frame_layout_calc_geometry): Set client height - as 0 when the window actually is shaded, not the other way around. - -2002-06-12 Havoc Pennington <hp@redhat.com> - - * src/theme.c (meta_frame_layout_calc_geometry): when a window is - shaded, don't include client height in the height calculation. - - * src/workspace.c (meta_workspace_get_neighbor): apply fix from - Mads Villadsen for the Up arrow key, #84582 - -2002-06-12 Havoc Pennington <hp@redhat.com> - - * src/theme.c (meta_frame_style_draw): Draw the buttons right - before the "overlay" piece. - -2002-06-12 Jayaraj Rajappan <jayaraj.rajappan@wipro.com> - - * src/tools/metacity-properties.glade: accessibility work for - metacity-properties capplet. Set appropriate atk relations. - Fixes bug #84749 - -2002-06-11 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_show): allow dialogs to steal focus - from panels/desktop - -2002-06-10 Jayaraj Rajappan <jayaraj.rajappan@wipro.com> - - * src/fixedtip.c: include <config.h> - fix for #83960 - -2002-06-10 Erwann Chenede - <erwann.chenede@sun.com> - - * src/keybindings.c : (handle_close_window, handle_minimize_window) - verify the active window has the appropriate close/minimize function - before closing or minimizing the window. - -2002-06-09 Havoc Pennington <hp@pobox.com> - - * configure.in: 2.3.987 - -2002-06-09 Havoc Pennington <hp@pobox.com> - - * src/delete.c (delete_ping_timeout_func): add G_IO_NVAL to watch - condition, patch from Gustavo Giraldez, avoids another 100% CPU - thingy - -2002-06-09 Havoc Pennington <hp@pobox.com> - - * src/place.c (meta_window_place): don't run constrain_placement - on windows we allow to go anywhere (docks, etc.). Fixes - positioning of panel windows in certain cases. - -2002-06-09 Havoc Pennington <hp@pobox.com> - - * src/frames.c (meta_frames_button_press_event): don't raise/focus - the window if minimize/close are clicked, patch from Gaute - Lindkvist #75460 - -2002-06-08 Havoc Pennington <hp@pobox.com> - - Cleanups to workspace popup patch. Space before all parens - in a couple places. - - * src/prefs.c (meta_prefs_get_keybinding_action): fix brace - indentation, and use while instead of for loop. Take a "mask" - argument to avoid ambiguity issues. - - * src/keybindings.c (handle_workspace_switch): rename from - handle_workspace_forward since there's no directionality here - (handle_workspace_switch): add a FIXME about how screwed it is - that we need a window in order to do our grab. Should be able to - grab on a dummy window like no_focus_window or the root window. - (process_workspace_switch_grab): rename from tab_grab for clarity, - no tab involved here. - - * src/common.h (enum): have only one grab op for all workspace - switching directions, instead of one for each. - -2002-06-08 Havoc Pennington <hp@pobox.com> - - Apply big patch from blackc@speakeasy.net adding a popup window - to the Ctrl+Alt+arrows shortcuts. #83940 - -2002-06-08 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_new): select key press/release on the - display->no_focus_window, another attempted fix for not getting - keybindings when no window is focused. Still doesn't seem to work - though. I don't get what's going wrong. - (meta_create_offscreen_window): new function, used instead of - XCreateSimpleWindow so we get override redirect offscreen windows. - -2002-06-08 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_open): set net_supporting_wm_check - in addition to win_supporting_wm_check, patch from - JeyaSudha for #83365 - - * src/screen.c (set_wm_check_hint): remove setting - win_supporting_wm_check on leader window here, done already in - display.c - -2002-06-08 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (meta_window_ungrab_keys): set keys_grabbed to - FALSE, patch from Jayaraj for #81857 - -2002-06-08 Havoc Pennington <hp@pobox.com> - - * src/xprops.c (meta_prop_get_utf8_string): don't die on bad atom - name - - * src/display.c (meta_display_close): don't unmanage windows here, - do it in screen_free and then closing the display unmanages - windows as a side effect of unmanaging the screen - (meta_display_unmanage_screen): new function - (process_selection_clear, process_selection_request): handle - selection stuff - (meta_spew_event): don't crash on client message containing - invalid atom - (meta_spew_event): don't crash on property notify with invalid - atom - - * src/main.c (main): add --replace option to replace existing - window manager. - - * src/screen.c: implement holding manager selection. - - * src/display.c (meta_display_open): add new selection-related - atoms. - -2002-06-08 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_new): select keypress/keyrelease - events on root window, this may fix the bug where keybindings - didn't work if you didn't have a focused window. - -2002-06-08 Havoc Pennington <hp@pobox.com> - - * src/main.c (main): call meta_session_shutdown when exiting - cleanly - - * src/session.c (meta_session_shutdown): function to change use to - RestartIfRunning - (meta_session_init): change normal restart hint to - RestartImmediately - -2002-06-08 Havoc Pennington <hp@pobox.com> - - Yeah I know maximization is broken, I'm too tired to fix it. - Probably because of the change to update_struts() that was - supposed to fix the 100% CPU bug. - - * src/place.c (meta_window_place): don't run docks and things - through the placement algorithm. Thought it might fix - metacity-window-demo but it didn't. - - * src/window.c (constrain_size): only get work area when needed - (meta_window_new): init the do_not_cover field - -2002-06-08 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_get_xinerama_for_window): - short-circuit the "only one xinerama" case, and use outer rect of - window instead of window->rect, so we get root window coords. - - * src/theme.c (meta_frame_layout_get_borders): if fullscreen all - frame edges are zero-width. - - * src/frame.c (meta_frame_get_flags): init fullscreen flag. - - * src/common.h (enum): add META_FRAME_FULLSCREEN frame flag - - * src/place.c: fix up calls to meta_window_get_work_area - - * src/window.c (meta_window_get_work_area): add an arg for whether - the work area is for the screen or the xinerama subscreen. - (constrain_position): fix up calls to meta_window_get_work_area - (constrain_size): ditto - - * src/screen.c (meta_screen_new): add METACITY_DEBUG_XINERAMA - environment variable which simulates xinerama on a single head. - -2002-06-08 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_struts): only invalidate things if the - struts actually change, since the panel likes to set them over and - over. May fix the infinite loop that caused 100% CPU usage. - -2002-06-07 Havoc Pennington <hp@redhat.com> - - * src/screen.c (meta_screen_new): use XineramaIsActive() not - XineramaQueryExtension() - -2002-06-07 Havoc Pennington <hp@redhat.com> - - * src/screen.c (meta_screen_get_current_xinerama): don't return - null on non-multihead - -2002-06-06 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_get_current_xinerama): implement - - * src/place.c (meta_window_place): cascade windows on the active - Xinerama screen - - * src/window.c (meta_window_move_resize_internal): strip out the - #if 0 cruft about guessing fullscreen mode - (constrain_position, constrain_size): fullscreen/maximize to the - Xinerama head, not the whole screen - (meta_window_get_work_area): autocreate struts at the Xinerama - physical screen edges for the screen the window is on. - - * src/screen.c (meta_screen_get_xinerama_for_window): someone - snuck in a for loop, fix it. ;-) - -2002-06-06 James M. Cape <jcape@ignore-your.tv> - - * src/themes/Esco/metacity-theme-1.xml: Increase the border size - of the buttons so they aren't quite so huge on my box. Also get - a *little* closer to finally fixing the horizontal line behind - the icon. It now works decently with common font sizes (in pixels). - -2002-06-05 Havoc Pennington <hp@pobox.com> - - * src/theme.c (meta_color_spec_new_from_string): parse - "shade/foo/factor" as a color - (colorize_pixbuf): remove the unused hsv_to_rgb and vice-versa - stuff, add the gtk_style_shade stuff. - (meta_color_spec_render): render the shaded color spec - - * src/theme.h (struct _MetaColorSpec): add "shade" mode to - MetaColorSpec. - -2002-06-04 Seth Nickell <snickell@stanford.edu> - - * src/metacity.desktop.in: - - Add X-GnomeWMSettingsLibrary to desktop file to support new - Window capplet. - -2002-06-04 Havoc Pennington <hp@redhat.com> - - * src/window.c (update_wm_hints): fix for how we read the input - hint, from Hidetoshi Tajima - - (meta_window_show): from Hidetoshi, don't autofocus windows with - input = FALSE wm_take_focus = FALSE when they first appear. We do - allow these windows to be focused (so keynav works), but they - don't get focused automatically. Now how do we keep them out of - the task list? - -2002-06-04 Gustavo GirÃ�¡ldez <gustavo.giraldez@gmx.net> - - * src/theme.c (draw_op_as_pixbuf): Use icon's instead of image's - fill_type when type is META_DRAW_ICON. - -2002-06-03 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_new): don't automatically fullscreen - things opened fullscreen, because there's no GUI to un-fullscreen - them. - -2002-06-03 Havoc Pennington <hp@pobox.com> - - * src/theme-parser.c (parse_aspect_ratio): fix error message about - bad aspect ratio name. - -2002-06-03 Havoc Pennington <hp@pobox.com> - - * src/themes/Esco/metacity-theme-1.xml: test button aspect ratio - instead of hardcoded button size, James feel free to revert if you - don't like it this way. - - * src/theme-parser.c: parse the aspect_ratio element for button - aspect ratios. - - * src/theme.h (struct _MetaFrameLayout): allow button sizes to be - given as an aspect ratio derived from the titlebar height, - instead of as a fixed size. - - * src/theme.c (meta_frame_layout_validate): validate new button - sizing parameters - - * src/theme.c (meta_frame_layout_calc_geometry): use new button - layout params - -Mon Jun 3 15:12:11 2002 HideToshi Tajima <hidetoshi.tajima@sun.com> - - * configure.in (METACITY_LIBS): put -lXext into SHAPE_LIBS - -2002-06-03 Kjartan Maraas <kmaraas@gnome.org> - - * src/tools/metacity-properties.desktop.in: Someone forgot to mark - the two strings in here for translation :) - -2002-06-02 Havoc Pennington <hp@pobox.com> - - * configure.in: 2.3.610 - -2002-06-01 Havoc Pennington <hp@pobox.com> - - * src/frames.c (meta_frames_finalize): move the remove_listener - to finalize instead of destroy, thanks to Jayaraj for tracking - down the bug. - -2002-06-01 Havoc Pennington <hp@pobox.com> - - * src/session.c: add some missing \n - (meta_session_init): remove the #if 0 interact callback from our - initial SmcOpenConnection call, this arg to SmcOpenConnection - doesn't exist. - -2002-06-01 Havoc Pennington <hp@pobox.com> - - * src/session.c: put in more debug spew about the session - -2002-05-30 Havoc Pennington <hp@pobox.com> - - * src/Makefile.am (INCLUDES): use $(prefix)/@DATADIRNAME@/locale - for localedir to work with Solaris native gettext, patch from - Hidetoshi Tajima - - * src/tools/Makefile.am: ditto - -2002-05-31 Havoc Pennington <hp@redhat.com> - - * src/theme.c: add MetaImageFillType and implement TILE in - addition to the existing SCALE - - * src/theme.h (struct _MetaDrawOp): remove no-longer-used "alpha" - field - -2002-05-31 Havoc Pennington <hp@redhat.com> - - * src/theme.c (multiply_alpha): now just uses - meta_gradient_add_alpha - (draw_op_as_pixbuf): implement alpha gradients for tint, gradient, - and image draw ops, so I can implement garrett's stuff. - - * src/gradient.c (meta_gradient_add_alpha): new function to - multiply the alpha channel of a pixbuf by an alpha gradient - -2002-05-30 Havoc Pennington <hp@redhat.com> - - * src/main.c (main): verbose-log on startup whether we were - compiled with various extensions - - * src/display.c (meta_display_queue_retheme_all_windows): reapply - shape mask when changing themes, sucks to do it here though, makes - theme changing slower. Needs fixing. - - * src/theme-parser.c (parse_toplevel_element): parse rounded - corner options to frame_geometry - - * src/frames.c (meta_frames_apply_shapes): apply rounded corners - if requested by the theme - - * configure.in (HAVE_SHAPE): check for shape extension - -2002-05-30 Stephen Browne <stephen.browne@sun.com> - - * src/tools/metacity-properties.c: - Some day I'll make all my changes in one commit :) - Needed to rip out code for adding icon to the dialog since it was - removed from teh galde file in my previous change. - -2002-05-30 Stephen Browne <stephen.browne@sun.com> - - * src/tools/metacity-properties.glade: - Some UI changes demanded by Pat and Calum. - Make Close default response - Change mnemonic for Click so as not to clash with Close - -2002-05-30 Stephen Browne <stephen.browne@sun.com> - - * src/tools/metacity-properties.glade: changed window title - to match other control center dialogs - -2002-05-29 Havoc Pennington <hp@pobox.com> - - * src/session.c (meta_session_init): improve error about failing - to open session manager. - (shutdown_cancelled_callback): send SmcSaveYourselfDone when we - get cancelled - (interact_callback): implement an interact callback that complains - about lame clients that can't be saved. Still somewhat buggy - in that it sends InteractDone before the user has closed the - dialog. - -2002-05-29 Havoc Pennington <hp@redhat.com> - - * src/tools/metacity-mag.c: add a magnifier I'm using when making - themes. Not installed. - - * src/tools/metacity-properties.c: reindentation, show window, add - copyright info. - - * src/tools/metacity-properties.glade: make main window !visible - on startup, to avoid funkiness. - -2002-05-29 Jacob Berkman <jacob@ximian.com> - - * src/tools/Makefile.am (EXTRA_DIST): dist .desktop.in files - -2002-05-29 Stephen Browne <stephen.browne@sun.com> - - New simple metacity-properties dialog to configure focus mode - and auto raise. - - * configure.in: added build support for metacity-properties - * src/tools/Makefile: more build stuff - * src/tools/metacity-properties.c: added these files - * src/tools/metacity-properties.glade: - * src/tools/metacity-properties.desktop.in: - * src/tools/metacity-properties.png: - -2002-05-29 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_move_resize_internal): add code to - also guess that client wants to come out of fullscreen, then - #if 0 the whole deal, I'm not sure it's such a good idea. - -2002-05-29 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_move_resize_internal): guess if a - window meant to be fullscreen, and if so put it in that state. - -2002-05-28 Havoc Pennington <hp@pobox.com> - - * src/window.c (redraw_icon): handle missing frame, prevents segv - with undecorated windows. #83298 - -2002-05-28 Havoc Pennington <hp@pobox.com> - - Patch from Erwann Chenede for raise_or_lower keybinding - - * src/display.c, src/common.h: POINT_IN_RECT moved to a common - location, removed from here - (meta_rectangle_intersect): move here and make it public - - * src/prefs.c: add raise_or_lower keybinding - - * src/stack.c (meta_stack_get_below, meta_stack_get_above): add an - arg to only get windows within the same layer - - * src/keybindings.c (handle_raise_or_lower): add handling for a - "raise window if obscured, else lower" keybinding - -2002-05-28 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_configure_request): handle CWStackMode - in configure requests - (meta_window_new): if a window is opened at 0,0 and screen size, - put it in the fullscreen state. - (meta_window_new): remove old code that set the window position to - 0,0 if PPosition/USPosition unset, that will be handled by whether - we place the window or not. - -2002-05-28 Abel Cheung <maddog@linux.org.hk> - - * configure.in: Added "zh_TW" to ALL_LINGUAS. - -2002-05-27 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_new): search for the window's screen - by root window instead of Screen*, maybe it will help with - bug #82664 - -2002-05-27 Kjartan Maraas <kmaraas@gnome.org> - - * autogen.sh: Hook up intltoolize here. - * configure.in: Initialize intltool. - * src/metacity.schemas.in: Add this. - * src/metacity.desktop.in: Add this too - * src/Makefile.am: Hook up intltool support for .schemas and .desktop. - * Makefile.am: Dist the intltool files. - -2002-05-27 Anders Carlsson <andersca@gnu.org> - - * src/themes/Gorilla/metacity-theme-1.xml: Apparently someone - thinks my name is Anders Carlsom. Well, it's not. - (Thanks to Carl-Johan Kjellander for noticing.) - -2002-05-26 James M. Cape <jcape@ignore-your.tv> - - * src/themes/Esco/metacity-theme-1.xml: Remove borders from - Esco theme as well (didn't know you could), apparently fixed - the problem where the spacing between the icon & the title - got larger as the fontsize went up. - -2002-05-26 Havoc Pennington <hp@pobox.com> - - * src/themes/Atlanta/metacity-theme-1.xml: totally drop the - borders off of maximized windows. - -2002-05-26 Havoc Pennington <hp@pobox.com> - - Patch from Gaute Lindkvist so you can't move the panel or desktop - to only one workspace. - - * src/keybindings.c (handle_move_to_workspace): don't allow moving - window to another space if the window is always_sticky - - * src/window.c (recalc_window_features): set the always_sticky - field for desktop/dock windows. - (meta_window_show_menu): disable unsticking always sticky windows - via the menus - - * src/menu.c (meta_window_menu_new): disable workspace items - if requested - -2002-05-26 Matthias Warkus <mawarkus@gnome.org> - - * po/de.po: Added. - * configure.in: de added to ALL_LINGUAS - -2002-05-25 Erwann Chenede - <erwann.chenede@sun.com> - - * src/keybindings.c (rebuild_screen_binding_table, - rebuild_window_binding_table, - meta_change_keygrab): allow key grabbing for - unmodified keys (e.g F1, etc) fix #82630 - -2002-05-25 Anders Carlsson <andersca@gnu.org> - - * src/place.c: (get_vertical_edges), (get_horizontal_edges): - Take Xinerama screen edges into consideration. - - * src/screen.c: (meta_rectangle_intersect), - (meta_screen_get_xinerama_for_window): - * src/screen.h: - Add a new function that returns the xinerama monitor that - a window is on. - -2002-05-24 Havoc Pennington <hp@pobox.com> - - * src/window.c (menu_callback): follow windows to their new - workspace - - * src/keybindings.c (handle_move_to_workspace): follow windows to - their new workspace - -2002-05-24 Havoc Pennington <hp@pobox.com> - - * src/metacity.schemas: add minimize window binding - - * src/keybindings.c (handle_minimize_window): add minimize keybinding - -2002-05-24 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_show): change how focusing windows - on initial map works, so that we only steal focus from our - transient parent or from a panel/desktop, never from other - normal windows. - -2002-05-24 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_configure_request): modify to ignore - PPosition and USPosition once the window has been placed - -2002-05-24 Anders Carlsson <andersca@gnu.org> - - * src/window.c: Redraw the window frame when the icon changes. - Fixes #78543, reported by Kang Jeong-Hee. - -2002-05-23 Havoc Pennington <hp@pobox.com> - - * src/display.c (event_callback): also filter out LeaveNotify - with NotifyInferior - -2002-05-23 Jayaraj Rajappan <jayaraj.rajappan@wipro.com> - - * src/display.c (event_callback): fix for bugzilla bug #72314, - filter out LeaveNotify caused by grabs when in mouse focus mode. - -2002-05-23 Havoc Pennington <hp@pobox.com> - - * src/metacity.schemas: clean up the font preference - - * src/prefs.c: font pref - - * src/frames.c: pay attention to the font pref - -2002-05-23 Havoc Pennington <hp@pobox.com> - - Crack from Erwann - - * src/metacity.schemas: add autoraise crackrock - - * src/display.c (event_callback): autoraise window if autoraise is - enabled - - * src/prefs.c: autoraise crack - -2002-05-21 Havoc Pennington <hp@redhat.com> - - * src/window.c (constrain_position): fix positioning in fullscreen - mode, patch from Gustavo GirÃ�¡ldez - -2002-05-20 Alessio Frusciante <algol@firenze.linux.it> - - * configure.in: Added Italian to ALL_LINGUAS. - -2002-05-20 Pablo Saratxaga <pablo@mandrakesoft.com> - - * configure.in: Added Catalan (ca) and Azeri (az) to ALL_LINGUAS - -2002-05-17 Havoc Pennington <hp@redhat.com> - - * configure.in: 2.3.377 - -2002-05-16 Havoc Pennington <hp@pobox.com> - - * src/workspace.c (meta_workspace_get_neighbor): fix it, maybe - -2002-05-16 Havoc Pennington <hp@redhat.com> - - * src/window.c (constrain_position): lock desktop to position 0,0 - -2002-05-16 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_show): don't focus dock, desktop, - etc. windows on initial map, only windows that should have focus. - -2002-05-15 Havoc Pennington <hp@pobox.com> - - * src/workspace.c (meta_workspace_get_neighbor): use the layout - information to figure out up/down neighbors - - * src/display.c (event_callback): catch propertynotify on - _NET_DESKTOP_LAYOUT - - * src/screen.c (meta_screen_update_workspace_layout): keep track - of the layout of workspaces as set by the pager - -2002-05-15 James M. Cape <jcape@ignore-your.tv> - - * src/themes/Esco/metacity-theme-1.xml: Minor tweak to minimize - button. - -2002-05-14 Havoc Pennington <hp@pobox.com> - - * src/themes/Makefile.am (THEMES): add Esco theme from James Cape - -2002-05-12 Havoc Pennington <hp@pobox.com> - - * src/place.c (meta_window_place): move pposition/usposition - honoring code into here, instead of putting it in window.c. - Makes focusing new windows work, and cleans things up a bit. - #81585 - -2002-05-12 Havoc Pennington <hp@pobox.com> - - * src/main.c (main): turn on --g-fatal-warnings if - METACITY_G_FATAL_WARNINGS env variable is set. - -2002-05-11 Anders Carlsson <andersca@gnu.org> - - * src/display.c: (find_tab_forward), (find_tab_backward), - (meta_display_get_tab_next): - * src/display.h: - * src/keybindings.c: (handle_tab_forward), (handle_focus_previous): - Add screen argument to meta_display_get_tab_next, since we only - want windows on the same screen to appear in the tab chain. - - * src/screen.c: (meta_screen_new): - Or the event mask with existing events since gtk+ may listen to - certain events and we don't want to disable those events. - - (meta_screen_ensure_tab_popup): - * src/tabpopup.c: (meta_ui_tab_popup_new): - * src/tabpopup.h: - Add a screen number argument to meta_ui_tab_popup_new so we - can position the popup on the correct screen. - -2002-05-11 Havoc Pennington <hp@pobox.com> - - * src/main.c: include locale.h, fix from Hidetoshi Tajima - - * src/window.c (meta_window_new): disable show desktop mode when a - new window is managed. - -2002-05-11 Havoc Pennington <hp@pobox.com> - - * src/fixedtip.c (meta_fixed_tip_show): keep the tooltip - on the screen horizontally, #76825 - - * src/window.c (meta_window_handle_mouse_grab_op_event): end grab - op _after_ doing the final update of the move or resize. - Hopefully I didn't have a reason for the order I was using before. - -2002-05-10 Havoc Pennington <hp@pobox.com> - - * src/tools/metacity-window-demo.c: add override redirect test - window - - * src/stack.c (raise_window_relative_to_managed_windows): new - function, used to avoid moving windows above override redirect - popup windows. - - * src/display.c (event_callback): don't lower panels on - LeaveNotify if they have focus, #70895 - -2002-05-10 Havoc Pennington <hp@pobox.com> - - * src/window.c (constrain_position): when maximizing/fullscreening - something with a grid, like a terminal, center it in the - maximization area in case it can't fill the whole area. - #70554 - - * src/main.c (main): use g_strerror() to get proper UTF-8. - -2002-05-10 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (reload_modmap): put LockMask into the - ignored_modifier_mask so that caps lock doesn't mess up - keybindings. - -2002-05-10 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_focus): if window is not mapped after - the calc_showing, don't focus it, it's probably on another - workspace or something. - -2002-05-09 Havoc Pennington <hp@redhat.com> - - * src/frames.c (show_tip_now): DefaultScreen() returns the screen - number not Screen* - - * src/frame.c (meta_frame_sync_to_window): immediately repaint - frame whenever we resize it, if we're inside a grab operation. - - * src/frames.c (meta_frames_repaint_frame): new function - - * src/window.c (meta_window_new): initialize window's colormap - (meta_window_notify_focus): install the colormap for a window when - it gets focus, uninstall on unfocus. - - * src/window.h (struct _MetaWindow): store window's colormap - - * src/display.c (event_callback): note changes to window colormap - - * src/frame.c (EVENT_MASK): add ColormapChangeMask - -2002-05-09 Havoc Pennington <hp@redhat.com> - - * src/display.c (event_callback): make Alt+button2 do a resize - -2002-05-08 Anders Carlsson <andersca@gnu.org> - - * src/fixedtip.c (meta_fixed_tip_show): - #ifdef out call to gtk_window_set_screen, reported by - Erwann Chenede. - -2002-05-08 Anders Carlsson <andersca@gnu.org> - - * configure.in: - * src/display.c: (meta_display_open): - * src/fixedtip.c: (meta_fixed_tip_show): - * src/fixedtip.h: - * src/frames.c: (meta_frames_new), (show_tip_now): - * src/frames.h: - * src/menu.c: (meta_window_menu_new): - * src/ui.c: (meta_ui_new): - Add multi-screen support. Also add patch by Erwann Chenede - to make tooltips appear on the correct screen. - -2002-05-07 Anders Carlsson <andersca@gnu.org> - - * src/workspace.c (set_work_area_hint): Doh, only update - the tmp pointer when the screen matches. Fixes a segfault - when running with multiple screens. - - * src/display.c: (meta_display_open), (event_callback), - (meta_display_update_show_desktop_hint): - * src/display.h: - * src/screen.c: (set_supported_hint): - Fix atom name; it's _NET_SHOW_DESKTOP, not - _NET_WM_SHOW_DESKTOP. - - * src/frames.c: (meta_frames_unmanage_window): - Restore the mouse cursor to default when unmanaging a window. - -2002-05-06 Anders Carlsson <andersca@gnu.org> - - * src/display.c: (set_utf8_string_hint): - Fix an off-by-one error. - - (meta_display_open), - (event_callback), (meta_display_update_show_desktop_hint), - (meta_display_show_desktop), (meta_display_unshow_desktop): - * src/display.h: - * src/screen.c: (set_supported_hint): - Add support for _NET_WM_SHOW_DESKTOP, both as a message and - as a root window property. - -2002-05-05 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_unminimize): on unminimize, queue - calc_showing on all transients - (meta_window_activate): on activate, unminimize all a window's - ancestors, not just the window itself. - - * src/workspace.c (set_work_area_hint): don't increment "tmp" by - 16 unsigned long, increment by 4 - - * src/window.c (meta_window_free): if a window isn't minimized, - restore its WM_STATE to NormalState instead of IconicState, - since IconicState on initial window map means that the window - should be minimized. - - * src/workspace.c (meta_workspace_invalidate_work_area): queue an - idle to recompute the work area hint. - (set_work_area_hint): we need 4*num_workspaces ints, not just - num_workspaces. - - * src/screen.c (meta_screen_new): add work_area_idle field, - handle it on screen shutdown - - * src/common.h (META_PRIORITY_PREFS_NOTIFY, - META_PRIORITY_WORK_AREA_HINT): define some idle priorities - - * src/window.c (meta_window_calc_showing): hide windows if - their parent window is minimized - (meta_window_minimize): also queue_calc_showing on all - transients of the window being minimized - - * src/place.c (constrain_placement): function to apply - placement-time-only constraints, such as "not off the left of the - screen" - (meta_window_place): put dialogs down a bit over their parent, - not right at the top. - (meta_window_place): when centering a dialog, center it - on the current xinerama screen, rather than the entire - screen. - - * src/screen.c (meta_screen_get_current_xinerama): new function, - but not implemented - -2002-05-04 Havoc Pennington <hp@pobox.com> - - * src/frames.c (meta_frames_paint_to_drawable): chop out the - portion of the region that's outside the screen. - - * src/core.c (meta_core_get_screen_size): new function - (meta_core_get_frame_extents): new function - -2002-05-04 Havoc Pennington <hp@pobox.com> - - * src/frames.c (meta_frames_init): disable automatic GTK double - buffering, since it resulted in gigantic backing pixmaps the size - of the whole screen. - (meta_frames_paint_to_drawable): change to take a region argument; - punch the client area out of the expose region, then iterate over - rectangles in the region and draw each, manually doing - begin_paint_rect. Results in 4 long thin backing pixmaps - per frame repaint, instead of one large backing pixmap. - Suggested by Owen. - -2002-05-05 Bastien Nocera <hadess@hadess.net> - - * src/workspace.c: (meta_workspace_get_neighbor): - Wrap-around workspaces (ie. when on the last workspace, - "switch_to_workspace_right" goes back to the - first one) - -2002-05-05 Anders Carlsson <andersca@gnu.org> - - * src/metacity.schemas: Fix a spelling error and change - switch_to_workspace_up and switch_to_workspace_down to use - Ctrl+Alt since Nautilus uses Alt now. - -2002-05-04 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_net_wm_type): correctly print things if the - type_atom is unset - (meta_window_new): with workarounds disabled, always allow - self-placement for windows with PPosition or USPosition set. - -2002-05-03 Havoc Pennington <hp@redhat.com> - - * src/Makefile.am: fix for automake 1.5, patch from Tomasz Kloczko - -2002-05-03 Laszlo Peter <laca@sun.com> - - * configure.in: add the X libs to METACITY_MESSAGE_LIBS and - METACITY_WINDOW_DEMO_LIBS - -2002-05-02 Havoc Pennington <hp@redhat.com> - - * README: updates - - * configure.in: 2.3.233 - -2002-05-02 Bastien Nocera <hadess@hadess.net> - - * src/metacity.schemas: change the default for switch_to_workspace_* - to be <Control><Alt>arrow as just <Alt>arrow collides with some apps - (especially web browsers) - -2002-05-01 Havoc Pennington <hp@redhat.com> - - * src/screen.c (meta_screen_new): Xlib doesn't like NULL for out - arguments; fix for #80472 from lbedford - -2002-04-30 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c: finish mopping up mode_switch_mask field - - * src/display.h (struct _MetaDisplay): remove mode_switch_mask - field - -2002-04-30 Havoc Pennington <hp@pobox.com> - - * src/window.c (recalc_window_features): don't try to decorate - toolbars. - - * src/tools/metacity-window-demo.c: add menu and toolbar tests - - * src/place.c (meta_window_place): only dialogs should be centered - over parent, not anything with transient for set. - - * src/window.c (meta_window_configure_request): become more - fascist about window positioning if workarounds are disabled, and - less fascist if they are enabled. - - * src/metacity.schemas: add a "disable_workarounds" option. Kind - of crack-smoking. But we just can't get all applications - fixed. And I need no-workarounds mode to monitor which apps are - broken and what needs fixing in specs. - - * src/window.c (meta_window_configure_request): always allow - windows to resize themselves - - * src/keybindings.c (reload_modmap): don't filter out Mode_switch, - apparently some people bind window manager shortcuts to that. - -2002-04-30 Havoc Pennington <hp@redhat.com> - - * src/window.c (constrain_position): oops, fix - maximization. Pointed out by Gustavo GirÃ�¡ldez - -Tue Apr 30 06:24:09 2002 Jonathan Blandford <jrb@gnome.org> - - * src/menu.c: give Maximize/Unmaximize and Shade/Unshade the same - mnemonic for consistency's sake. - -2002-04-29 Havoc Pennington <hp@redhat.com> - - * src/window.c (TITLEBAR_LENGTH_ONSCREEN): require 36 pixels - onscreen so you typically get a sliver of titlebar, suggested by - tigert. Should still fix this to consider actual theme geometry. - (constrain_position): change to allow movement off the left - -2002-04-29 Havoc Pennington <hp@redhat.com> - - * src/display.c (event_callback): always raise windows on focus - click, regardless of focus mode. - -2002-04-29 Havoc Pennington <hp@redhat.com> - - * configure.in: 2.3.144 - -2002-04-29 Havoc Pennington <hp@pobox.com> - - * src/ui.c (meta_ui_init): don't leak the PangoContext - -2002-04-28 Anders Carlsson <andersca@gnu.org> - - * src/display.c: (meta_display_open): - * src/display.h: - * src/screen.c: (set_supported_hint): - * src/workspace.c: (set_number_of_spaces_hint), - (set_workarea_hint): - Add support for setting the _NET_WM_WORKAREA hint. No code - does it yet though. - -2002-04-28 Havoc Pennington <hp@pobox.com> - - * README: remove caveats about keybindings - - * src/metacity.schemas: add schemas for all the keybindings. - - * src/window.c (meta_window_activate): if in "show desktop" mode - when a window is activated, leave show desktop mode. So e.g. - when you click on a task in the task list, show desktop mode - will be turned off. - - * src/workspace.c (meta_workspace_get_neighbor): new function - that doesn't quite work yet (needs support for getting - workspace layout from the pager) - - * src/prefs.c: keybindings stuff - - * src/keybindings.c: make keybindings configurable - - * src/ui.c (meta_ui_parse_accelerator): new function - -2002-04-25 Havoc Pennington <hp@redhat.com> - - * metacity.spec: fix to install gconf schemas - -2002-04-25 jacob berkman <jacob@ximian.com> - - * src/session.c (load_state): g_file_get_contents() takes a gsize - not int (fixes bus error on 64-bit platforms) - -2002-04-22 Havoc Pennington <hp@redhat.com> - - * src/main.c (main): call setlocale ourselves because due to a - GLib bug that sticks us in ASCII if you call g_print or anything - prior to setlocale, and print a warning if we don't set the locale - successfully. #79280 - - * src/workspace.c (meta_workspace_get_work_area): be more verbose - about how the work area was computed, to help find bugs here. - - * src/main.c (main): put locale and codeset in the log file - -2002-04-21 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_send_icccm_message): add error trap, - fixes a possible BadWindow if a window closed itself in response - to the delete window message prior to us sending the ping message. - -2002-04-21 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_move_resize_now): never revert to - user_rect.width, user_rect.height. Maybe fixes assorted resize - screwups e.g. with gnome-terminal. - -2002-04-21 Anders Carlsson <andersca@gnu.org> - - * src/iconcache.c (scaled_from_pixdata): Add padding if - icon width and height differ. - -2002-04-17 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_new): query Xinerama screen - information if HAVE_XINERAMA - - * configure.in (found_xinerama): check for Xinerama - -2002-04-17 Changwoo Ryu <cwryu@debian.org> - - * configure.in (ALL_LINGUAS): Added ko (Korean). - -2002-04-16 Akira TAGOH <tagoh@gnome.gr.jp> - - * configure.in (ALL_LINGUAS): add ja.po entry. - -2002-04-15 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_title): fix issue with GNU libc - mangling %.10s format - - * metacity.spec: Fix up spec file - - * README: update README - - * configure.in (ALL_LINGUAS): require GTK 2.0.0 - -2002-04-15 Havoc Pennington <hp@redhat.com> - - * src/display.c (meta_display_ping_window): reply immediately for - windows that don't support _NET_WM_PING - - * src/window.c (update_protocols): check whether windows - support _NET_WM_PING - -2002-04-13 Havoc Pennington <hp@pobox.com> - - * src/ui.c (get_cmap): same fix as libwnck, avoid using cmap - with the wrong depth - -2002-04-13 Havoc Pennington <hp@pobox.com> - - * src/delete.c: new file containing all the - wacky mess I just added to a simple "click the close button", - contains all the dealing-with-dead-application cruft. - Use metacity-window-demo to test by clicking the - toolbar button that locks it up. - -2002-04-12 Havoc Pennington <hp@redhat.com> - - * src/tools/metacity-window-demo.c (do_appwindow): make one of the - toolbar buttons lock up the demo - - * src/window.c (meta_window_delete): move error trap to be around - a narrower part of the function, and add part of the ping stuff, - nothing user-visible yet - - * src/metacity-dialog.c (main): metacity-dialog executable to - live in libexecdir and pop up dialogs for us. - -2002-04-09 Havoc Pennington <hp@pobox.com> - - * src/theme.c (multiply_alpha): fix alpha multiplication routine - to perhaps work correctly, reported by tigert. Also, be sure - we always copy the image if necessary before modifying the - alpha channel. - -2002-04-05 Havoc Pennington <hp@pobox.com> - - * src/stack.c: remove the unused tab stuff - - * src/display.c: implement tab list among panels - - * src/keybindings.c: fill in move-between-panels keybindings - -2002-03-31 Johan Dahlin <jdahlin@telia.com> - - * src/menu.c (meta_window_menu_new): Make sure all menu items are - translated. - -2002-03-27 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_free): remove - unmanaged windows from save set, and unselect - input so we don't get events from them. Fixes annoying - bug where withdrawn windows would decide to map themselves - due to save set stuff. - -2002-03-22 Zbigniew Chyla <cyba@gnome.pl> - - * configure.in (ALL_LINGUAS): Added pl (Polish). - -2002-03-21 Havoc Pennington <hp@pobox.com> - - * src/themes/Bright/metacity-theme-1.xml: Added "Bright" theme - from Gaute Lindkvist, with some small clipping tweaks to keep - text/icons from overlapping their frames. - -2002-03-19 Havoc Pennington <hp@redhat.com> - - * src/resizepopup.c (place_vertical_size_window) - (place_horizontal_size_window): disable the little shaped windows - with the window size, they caused a crash anytime you tried to - resize with Xft. And they were kind of on crack anyway. - -2002-03-17 Havoc Pennington <hp@pobox.com> - - * src/resizepopup.c (ensure_tick_windows): turn off the tick - marks, that got annoying after about 5 minutes. One big shape - window instead of lots of little windows might fix it. - -2002-03-17 Havoc Pennington <hp@pobox.com> - - * src/resizepopup.c: Add some total crackrock resize-grid - indication for windows that have width_inc/height_inc - so I can debug gnome-terminal sizing. - -2002-03-17 Havoc Pennington <hp@pobox.com> - - * src/session.c (set_clone_restart_commands): use proper property - name for SmDiscardCommand (instead of setting the clone command to - "rm"). Also fix typo that iterated over clonev not discardv to - fill in prop list, and NULL-terminate discardv. #74584 from Kang - Jeong-Hee. - -2002-03-13 Havoc Pennington <hp@pobox.com> - - * src/main.c (main): put back --sm-client-id argument, needed - for including us in a default session - -2002-03-13 Havoc Pennington <hp@pobox.com> - - * src/session.c (meta_session_init): don't save a file here, only - in response to SaveYourself. Change the code to properly use a - unique state file for each SaveYourself. Totally, totally - untested. - -2002-03-12 Havoc Pennington <hp@pobox.com> - - * src/theme-viewer.c: improve the theme viewer so people - can see the broken aspects of their themes. - -2002-03-11 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c: use new functions - - * src/display.c (meta_display_get_tab_next): - (meta_display_get_tab_list): new tab order functions using - MRU list instead of map order - - * src/window.c (meta_window_notify_focus): maintain focus MRU list - - * src/display.h (struct _MetaDisplay): Keep an MRU list of - windows. - -2002-03-10 Havoc Pennington <hp@pobox.com> - - * src/display.c (event_callback): support _NET_NUMBER_OF_DESKTOPS - message so you can change number of desktops with the pager - - * src/prefs.c (meta_prefs_set_num_workspaces): new function - - * src/display.c (meta_spew_event): print stacking aspects of - configure requests - -2002-03-10 Havoc Pennington <hp@pobox.com> - - * src/screen.c (set_supported_hint): we didn't claim to support - _NET_ACTIVE_WINDOW so gtk_window_present() didn't work. Mumble. - Only worked with tasklist because libwnck didn't check for - WM support. - - * src/window.c (meta_window_free): clean off window state - when windows are withdrawn, to avoid sticking dialogs - to their initial desktop. - (meta_window_queue_calc_showing): return if window is withdrawn - -2002-03-08 Laszlo Peter <laca@ireland.sun.com> - - * configure.in: fix the X linker flags - -2002-03-06 Havoc Pennington <hp@pobox.com> - - * src/core.c (meta_core_get_grab_frame): add some assertions - - * src/menu.c (meta_window_menu_new): make another warning - into a verbose - - * src/display.c (meta_change_button_grab): use verbose rather than - warning to log failures to grab button, since these are typically - BadWindow from a destroyed window. - -2002-03-06 Havoc Pennington <hp@redhat.com> - - * src/frames.c (meta_frames_manage_window): use hash_table_replace - instead of g_hash_table_insert - - * src/main.c (main): only enable verbose/debug if you set - METACITY_VERBOSE/METACITY_DEBUG - - * src/util.c (ensure_logfile): only use a log file if - METACITY_USE_LOGFILE is set - - * src/display.c (meta_display_for_x_display): add warning if - MetaDisplay isn't found - - * src/window.c (meta_window_free): add an assertion that we - successfully cleared the grab window - -2002-03-05 Havoc Pennington <hp@pobox.com> - - Work on opaque animations more, still suck too much - to turn on. Not sure how to make them good. - - * src/effects.c (meta_effects_draw_box_animation): - add a slide-up mode for shading - - * src/ui.c (meta_image_window_set): change image window to work by - setting back pixmap on the GtkWindow, instead of using GtkImage. - -2002-03-04 Havoc Pennington <hp@pobox.com> - - * src/main.c (main): try ignoring SIGXFSZ, though I'm not - sure what that does exactly. I'm hoping it gives me EFBIG. - - * src/util.c (ensure_logfile): log to a file in /tmp instead - of to ~/metacity.log. - -2002-03-04 Havoc Pennington <hp@redhat.com> - - * configure.in: fix configure.in since GTK no longer gives us - -L/usr/X11R6/lib - -2002-03-03 Havoc Pennington <hp@pobox.com> - - * src/window.c: improve debug spew about initial workspace - -2002-03-02 Havoc Pennington <hp@pobox.com> - - * src/window.c (recalc_window_features): disable resize etc. if - we're fullscreen - (constrain_size): fix size constraints when fullscreen - - * src/display.c (meta_display_open): fix missing comma that - ended up concatenating two of the properties breaking - FULLSCREEN state and PING protocol - -2002-03-02 Havoc Pennington <hp@pobox.com> - - * src/display.c: Add hacking to fix the problem that we made our - XGrabPointer() during Alt+Tab actually succeed, so on popping down - Alt+Tab we got an EnterNotify from the ungrab, which resulted in - focusing the window under the mouse. i.e. Alt+Tab didn't work with - sloppy focus. - -2002-02-26 Havoc Pennington <hp@pobox.com> - - Screw around with Anders's ping patch so he'll get plenty of CVS - conflicts. ;-) - - * src/display.c (meta_display_ping_window): spew warnings - if we try to call this with CurrentTime - (meta_display_ping_timeout): remove ping from the pending pings - after it times out. - - * src/util.h: added PING debug category - - * src/display.c (remove_pending_pings_for_window): don't remove - "tmp" just before "tmp->next", don't break out of loop after - finding the first match - (meta_display_open): no trailing comma in array init - (event_callback): move the processing of ping replies into a - separate function - - * src/screen.c (set_supported_hint): add _NET_WM_PING to supported - list - - * src/display.h: change gpointer to void* - -2002-02-26 Anders Carlsson <andersca@gnu.org> - - * src/display.c: (ping_data_free), - (remove_pending_pings_for_window), (meta_display_open), - (event_callback), (meta_display_unregister_x_window), - (meta_display_ping_timeout), (meta_display_ping_window), - (meta_display_window_has_pending_pings): - Implement meta_display_ping_window, and filter out scroll wheel - events. - - * src/display.h: - Add MetaWindowPingFunc, meta_display_ping_window and - meta_display_window_has_pending_pings. - -2002-02-24 Havoc Pennington <hp@pobox.com> - - * src/display.c (xcursor_for_op): switch on the op passed in, not - the active op. Gives us the right cursor during resizing, etc. - - * src/errors.c: rearrange all the error stuff to adapt to the GDK - change a while back, so now we print our X errors again - - * src/display.c (meta_display_begin_grab_op): remove KeyPressMask - and KeyReleaseMask from the XGrabPointer(), this caused BadValue - and kept the grab from ever succeeding. Fixes the problem with the - GTK resize grip - this is why you shouldn't break your X error - spew. ;-) - - * src/display.c: debug spew tweaks - - * src/window.c (meta_window_client_message): do some - s/verbose/topic/ stuff - -2002-02-23 Havoc Pennington <hp@pobox.com> - - * src/ui.c (meta_ui_init): fix the - be-sure-we-create-coverage-cache hack - -2002-02-19 Havoc Pennington <hp@pobox.com> - - * src/ui.c (meta_ui_init): put in hack to keep Pango from mangling - our server grab and locking up on startup. (hack doesn't work - but I want to fix it on my real computer not this laptop) - - * src/window.c: Implement _NET_WM_STATE_FULLSCREEN - - * src/display.c (meta_display_open): add atoms for - _NET_WM_STATE_FULLSCREEN - -2002-02-16 Kjartan Maraas <kmaraas@gnome.org> - - * src/main.c: Use bind_textdomain_codeset etc. - -2002-02-14 Havoc Pennington <hp@pobox.com> - - * src/theme-viewer.c: use the preview widget here - - * src/preview-widget.h, src/preview-widget.c: make the theme - preview into a nice widget - - * src/frames.c (meta_frames_ensure_layout): replace frame layout - if the frame style changes, this only ends up mattering if you - e.g. changed the font size for windows in a different state such - as maximized, which is crack, but the code may as well be correct - - * src/theme.c (meta_theme_get_frame_style): new function so we can - detect an invalid cache of the PangoLayout in a frame - -2002-02-14 Anders Carlsson <andersca@gnu.org> - - * src/themes/Crux/metacity-theme-1.xml: Fix some bugs with - prelighting. - -2002-02-13 Anders Carlsson <andersca@gnu.org> - - * src/theme.c (meta_pango_font_desc_get_text_height): Use - pango_context_get_metrics instead of loading the font. - -2002-02-12 Anders Carlsson <andersca@gnu.org> - - * src/frames.c (meta_frames_manage_window): Set prelit_control - to META_FRAME_CONTROL_NONE. - (meta_frames_update_prelit_control): New function for setting - the prelit control. - (meta_frames_paint_to_drawable): Set prelight state. - (meta_frames_enter_notify_event): Update prelit control. - (meta_frames_leave_notify_event): Likewise. - (meta_frames_motion_notify_event): Likewise. - - * src/frames.h (struct _MetaUIFrame): add prelit_control. - - * src/window.c (update_mwm_hints): and MWM_FUNC_ALL - with hints->functions instead of hints->flags. - -2002-02-11 Anders Carlsson <andersca@gnu.org> - - * src/theme.c (meta_frame_layout_new): Set title_scale to 1.0 - -2002-02-11 Bastien Nocera <hadess@hadess.net> - - * src/theme-viewer.c: (main): change default theme to be Atlanta - like in the .schema file - -2002-02-10 Havoc Pennington <hp@pobox.com> - - * src/tools/Makefile.am (EXTRA_DIST): add $(icon_DATA) - - * configure.in: 2.3.55 - - * HACKING: update - - * README: update - -2002-02-09 Havoc Pennington <hp@pobox.com> - - * src/theme.c (meta_theme_set_current): add a newline to an error - message - - * src/themes/Gorilla: add Gorilla theme by Jakub Steiner ported to - metacity by Kenneth Christiansen - -2002-02-09 Havoc Pennington <hp@pobox.com> - - * src/theme.c (meta_draw_op_draw_with_env): implement wacky "tile" - draw op to lose some of the PNG files in Gorilla theme - - * src/theme-parser.c: parse the tile primitive - -2002-02-09 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_icon): port to icon cache - - * src/iconcache.c, src/iconcache.c: begin process of cleaning up - window.c by moving the icon-reading code in here, based on the - code in libwnck, which was in turn based on the earlier metacity - code - -2002-02-09 Havoc Pennington <hp@pobox.com> - - * src/stack.c (meta_stack_sync_to_server): hmm, and don't set - last_window at all if we don't ++newp. Fixes even more obscure - stacking bug. - -2002-02-09 Havoc Pennington <hp@pobox.com> - - * src/stack.c (meta_stack_sync_to_server): assign last_window - prior to ++newp, so we don't try to stack windows with respect to - themselves. Fixes some obscure stacking bugs. - -2002-02-09 Havoc Pennington <hp@pobox.com> - - * src/theme-parser.c: try to make more error message strings the - same, easier for translators - - * src/theme.c (meta_draw_op_free): free color spec for line op - (meta_theme_free): free the integer_constants hash - - * src/theme-parser.c (parse_boolean): move above first use - - * src/theme-viewer.c: fixes for theme.h changes - - * src/frames.c (queue_recalc_func): don't recreate layout - immediately, just save title text. should speed things up. - (meta_frames_set_title): just remove the layout here also, - and save title text. - - * src/theme-parser.c (parse_toplevel_element): parse title_scale - attribute on frame_geometry - - * src/theme.c: support setting the text size - - * src/frames.c: support setting the text size - - * theme-format.txt: updates - -2002-02-09 Havoc Pennington <hp@pobox.com> - - * src/themes/Atlanta/metacity-theme-1.xml: put in some kind of - distinctive frame for UTILITY, though it's ugly. Also put in the - borderless look for maximized windows. - - * src/stack.c (compute_layer): put splash screen in the splash - layer - - * src/stack.h (enum): create a splash screen layer - - * src/place.c (meta_window_place): center splashscreen, and fix a - typo in the centering code - - * src/window.c (recalc_window_features): disable most features on - splash screens - - * src/screen.c (set_supported_hint): add UTILITY and SPLASHSCREEN - hints - - * src/window.c: add UTILITY, SPLASHSCREEN implementation - - * src/window.h (enum): add UTILITY, SPLASHSCREEN types - - * src/theme-parser.c (parse_toplevel_element): parser support - for has_title attribute - - * src/theme.c (meta_frame_layout_get_borders): handle a has_title - field in the layout, for utility windows that don't display a - title (would be better to be able to shrink the title text, - but that's kind of tricky to implement :-/) - -2002-02-08 Havoc Pennington <hp@pobox.com> - - * src/screen.c (set_supported_hint): add _NET_WM_STATE_HIDDEN - to _NET_SUPPORTED - - * src/keybindings.c (meta_set_keybindings_disabled): put in header - file, to fix warning. - - * src/display.c (meta_display_open): add _NET_WM_STATE_HIDDEN atom - - * src/window.c (set_net_wm_state): set _NET_WM_STATE_HIDDEN for - shaded and minimized windows - (meta_window_show): call set_net_wm_state() if we map the window - or frame - (meta_window_hide): call set_net_wm_state() if we unmap the window - or frame - -2002-02-08 Havoc Pennington <hp@pobox.com> - - * src/window.c (set_net_wm_state): only set skip pager/tasklist if - the app set it, don't set it again based on semantic type. - -2002-02-08 Anders Carlsson <andersca@gnu.org> - - * src/theme.c (scale_and_alpha_pixbuf): If we're only - scaling horizontally or vertically, use GDK_INTERP_NEAREST. - -2002-02-08 Havoc Pennington <hp@pobox.com> - - * autogen.sh: unbreak - -2002-02-08 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_grab_focus_window_button): grab - buttons 2 and 3 also, so you can focus a window with those, - #70840 - (event_callback): fix this to let you focus a window with any - unmodified click, and also with Alt+button1 - - * configure.in (AC_OUTPUT): add po/Makefile.in - - * autogen.sh: port to glib-gettextize, remove stupid - auto-find-subdirs crap - - * Makefile.am (SUBDIRS): add po to subdirs, #70615 - - * src/window.c (meta_window_activate): unshaded window if shaded, - I thought this was in bugzilla but I don't see it. anyway thanks - whoever mentioned it to me. - -2002-02-08 Havoc Pennington <hp@pobox.com> - - * src/tools/metacity-window-demo.c (menu_items): add modal dialog test - -2002-02-08 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_show): when mapping a window with - struts, invalidate the work areas it's on. Should fix at least - part of the problem with windows maximizing over panels. - - * src/workspace.c (meta_workspace_invalidate_work_area): also - queue move/resize on sticky windows - - * src/tools/Makefile.am: consolidate reload-theme, restart into a - "metacity-message" app and add enable/disable keybindings to the - messages it knows about. - - * src/keybindings.c: - (meta_change_keygrab): grab keyboard synchronously - (meta_display_process_key_event): if all keybindings are toggled - off, ReplayKeyboard, else AsyncKeyboard, except that the debug - binding for toggling back on is always processed - (meta_set_keybindings_disabled): function to disable/enable - all keybindings - -2002-02-07 Havoc Pennington <hp@pobox.com> - - * src/run-metacity.sh: if DEMO_TEST is set then run the window - demo - - * src/tools/metacity-window-demo.c: Create an app with all the - semantic window types, for testing and for designing themes. - -2002-02-07 Havoc Pennington <hp@pobox.com> - - Throughout: move to meta_topic rather than meta_verbose so - metacity.log can start being more useful - - * src/util.h (enum): add more debug topics - - * src/frames.c: clean up some cruft that caused warnings - -2002-02-07 Havoc Pennington <hp@pobox.com> - - * src/theme.c (colorize_pixbuf): do random voodoo on the algorithm - -2002-02-07 Havoc Pennington <hp@pobox.com> - - * src/theme.c (colorize_pixbuf): use the intensity of the gray - pixel for both saturation and value, not just value. - -2002-02-07 Havoc Pennington <hp@pobox.com> - - * src/theme.c (INTENSITY): don't define the macro twice - -2002-02-07 Havoc Pennington <hp@pobox.com> - - * src/theme.c (colorize_pixbuf): get algorithm right (use HSV/RGB - conversion) at cost of making it a lot slower. It doesn't matter - anyhow with the cache, though. - -2002-02-06 Havoc Pennington <hp@pobox.com> - - * src/theme.c (colorize_pixbuf): handle out-of-memory creating - target pixbuf - - * src/themes/Crux/*.png: convert the green-channel images to grayscale - -2002-02-06 Havoc Pennington <hp@pobox.com> - - * src/prefs.c (change_notify): s/update_focus_mode/update_theme/ - in case of theme key changing - -2002-02-06 Havoc Pennington <hp@pobox.com> - - * src/theme-viewer.c: benchmark theme on startup - - * src/theme-parser.c (parse_draw_op_element): fix "colorize != - NULL" to "colorize_spec != NULL" and free pixbuf on color spec - failure - - * src/theme.c (colorize_pixbuf): minor reformatting, raise - function calls out of inner loop, clamp r/g/b values to uchar - range before assigning to uchar - (draw_op_as_pixbuf): cache the colorized pixbuf - (meta_draw_op_free): free the cache pixbuf - -2002-02-07 Anders Carlsson <andersca@gnu.org> - - * src/theme-parser.c: (parse_draw_op_element): - Add support for "colorize" image attribute. - - * src/theme.c: (colorize_pixbuf): - New function that colorizes a pixbuf. - - (pos_tokenize): Allow "\n" as a whitespace character. - - (meta_draw_op_free): Free colorize_spec; - - (draw_op_as_pixbuf): Colorize image if needed. - - * src/theme.h: Add colorize_spec to struct. - -2002-02-07 Anders Carlsson <andersca@gnu.org> - - * src/themes/Crux/metacity-theme-1.xml: Add maximized and - shaded_and_maximized frame styles. - -2002-02-06 Havoc Pennington <hp@pobox.com> - - * src/main.c (prefs_changed_callback): redo window - sizes/appearance when the theme changes - - * src/display.c (meta_display_retheme_all): new function - - * src/theme-parser.c (locate_attributes): remove error handling - for MAX_ATTRS reached, add an assert instead, the way this code - ended up the attrs in the array depend on the code not the theme - file. - -2002-02-06 Havoc Pennington <hp@pobox.com> - - * src/main.c (main): disable custom log handler and fatal mask for - now - - * src/theme.c (meta_draw_op_list_draw): - Add META_DRAW_CLIP - - * src/main.c: load theme, monitor current theme setting - - * src/prefs.c: add "current theme" setting - - * src/stack.c (meta_stack_free): don't try to free - last_root_children_stacked if it doesn't exist - - * src/themewidget.c: pluggable GtkMisc subclass to use - for menu icons - - * src/screen.c (meta_screen_manage_all_windows): fix - signed/unsigned warning - - * src/frames.c: port to theme system - (meta_frames_style_set): chain up - - * theme-format.txt: new file - - * configure.in: add more compiler warnings - - * src/theme.c: add various stuff needed to get theme parser - working. Remove the "spacer" concept from FrameLayout object. - Add draw op that references a draw op list. - - * configure.in: require GTK 1.3.13 - - * src/Makefile.am: add theme-parser.[hc], implement loading a - theme - - * src/theme.c: add "draw title" and "draw window icon" operations - (meta_draw_op_draw): put object_width/object_height in expression - environment before computing x/y. Handle out-of-memory when - creating pixbufs. Assorted other cleanups. - -2002-02-07 Anders Carlsson <andersca@gnu.org> - - * src/themes/Crux/metacity-theme-1.xml: - Simplify things so we can remove some - now unnecessary .png files. - * src/themes/Crux/*.png: Remove some files. - -2002-02-07 Anders Carlsson <andersca@gnu.org> - - * src/themes/Crux/metacity-theme-1.xml - * src/themes/Crux/*.png: - Add Crux theme - -2002-02-07 Kenneth Rohde Christiansen <kenneth@gnu.org> - - * configure.in: add da to ALL_LINGUAS - * po/da.po: add Danish translation - -2002-02-02 Havoc Pennington <hp@pobox.com> - - * src/theme-viewer.c: test % operator - - * src/theme.c (pos_tokenize): add % to switch for operators - - * src/theme.c: rework theme stuff so we have - MetaDrawOp/MetaDrawOpList instead of MetaTextureSpec/MetaShapeSpec - -2002-01-28 Havoc Pennington <hp@pobox.com> - - * src/theme.c (meta_texture_spec_render): fix shadowed variable - (stupid -Wall should have that) - - * src/theme-viewer.c (main): implement a simple - viewer for frame styles - - * src/theme.c (meta_frame_style_get_test): create partial - frame style to test drawing - -2002-01-27 Havoc Pennington <hp@pobox.com> - - * src/theme.c (meta_shape_spec_draw): implement - (meta_texture_spec_draw): implement shape spec and blank - texture support - (meta_frame_style_draw): implement - -2002-01-27 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_set_syncing): move in here so util.c doesn't - require display.[hc] - - * src/theme.h, src/theme.c: implement coordinate expression - parser, write MetaShapeSpec declaration - - * src/util.c (meta_exit): move in here so we can link - to util.c with a different main() - - * src/theme.h: rename the MetaWindow* enums to MetaFrame* - -2002-01-27 Peteris Krisjanis <peteris.krisjanis@ttc.lv> - - * configure.in - Added lv to ALL_LINGUAS - -2002-01-27 Havoc Pennington <hp@pobox.com> - - * src/frames.c (get_control): Only consider the bottom of the - titlebar a resize control; I keep accidentally resizing windows - instead of activating them. Also, give south resizing priority - over north, if the window is so small the active regions overlap - - * src/theme.c: add MetaTheme, get MetaFrameStyleSet into - a usable state - - * src/common.h: move window type back to window.h, decided - not to use it on frame side - (MetaFrameType): add this instead - -2002-01-27 Havoc Pennington <hp@pobox.com> - - * src/theme.h, src/theme.c: implement all kinds of crazy - compositing-one-texture-onto-another BS. - -2002-01-27 Havoc Pennington <hp@pobox.com> - - * src/display.c (event_callback): make the check for whether to - eat focus click a lot more complicated - - * src/window.c (meta_window_same_application): new function - - * src/prefs.h, src/prefs.c: add application based pref - - * src/metacity.schemas: add "application_based" setting to - give me a mode to fool with being application based, - without being unusable in the meantime. Yeah the crack flows - freely these days. Everyone knew it would happen. - -2002-01-27 Havoc Pennington <hp@pobox.com> - - * src/frames.c: separate code to draw frame from the - expose_event handler, so in principle we can draw the - frame to a pixmap, but this isn't used yet. - -2002-01-22 Hasbullah Bin Pit <sebol@ikhlas.com> - - * configure.in: Added Malay (ms)to ALL_LINGUAS. - * po/ms.po: Added Malay Translation. - -2002-01-19 Havoc Pennington <hp@pobox.com> - - * src/wm-tester/test-resizing.c: cheesy client with static - bit gravity, used to test the below change. - - * src/window.c (meta_window_move_resize_internal): implement - Owen's proposal for window resizing. - http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html - - Currently you have to do METACITY_USE_STATIC_GRAVITY=1 in order to - use it, because some GDK bug is screwing up exposes on my frames - when it's enabled. - - * src/display.c (meta_display_create_x_cursor): fix glyph for - NE/NW cursors - - * src/frames.c (get_control): add ability to resize from top - - * src/frame.c (meta_frame_get_flags): can't resize shaded windows - (meta_frame_sync_to_window): add gravity arg - - * src/common.h (MetaWindowType): move here from window.h so - it can be used in themes stuff. - (MetaFrameFlags): remove META_FRAME_TRANSIENT since it - overlaps with window type and was unused. - -2002-01-18 Havoc Pennington <hp@pobox.com> - - * src/window.c (constrain_position): give priority to keeping NW - corner onscreen rather than SE, if we need to shift the window - to fit inside constraints - - * src/frames.c (meta_frames_get_geometry): don't depend on the - current window size - - * src/theme.c: move geometry stuff in here, to be calculated as - part of the theme - - * src/core.c (meta_core_get_client_size): new function to replace - meta_core_get_frame_size() so we don't have weird cycles - in the geometry calculation - -2002-01-12 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_queue_move_resize): make this actually - queue, rather than being synchronous as it was before. We'll see - what breaks. Should be more efficient and reduce flickery stuff a - bit in some cases. - -2002-01-15 Havoc Pennington <hp@redhat.com> - - * src/keybindings.c (handle_tab_backward): fix crash - when grab failed due to another operation in progress - (handle_tab_forward): fix crash when grab failed - -2002-01-10 Havoc Pennington <hp@pobox.com> - - * src/frame.c (meta_window_destroy_frame): only bump - unmaps_pending if the window was mapped - (meta_window_ensure_frame): ditto - - * src/keybindings.c: change arrow key bindings to use Ctrl+Alt not - just Alt, and add debug mode key bindings - - * src/stack.c (meta_stack_get_default_focus_window): don't choose - a default focus window with unmaps pending, since we probably just - unmapped it. - - * src/display.c (event_callback): move notify_focus on UnmapNotify - after the window_free check, so we can move focus to another - window when we unmanage - - * src/window.c (meta_window_hide): invalidate work areas when - hiding a window with struts - (meta_window_free): invalidate work areas when unmanaging a window - with struts - -2002-01-09 Havoc Pennington <hp@pobox.com> - - * src/window.c, src/window.h: store strut information, - update it on property changes, etc. etc. so we avoid panel - on maximize. - - * src/workspace.c (meta_workspace_get_work_area): add accessor for - work area so we can compute it lazily - - * src/display.h, src/display.c: add _NET_WM_STRUT atom - and _WIN_HINTS atom - -2002-01-08 Havoc Pennington <hp@pobox.com> - - * configure.in (ACLOCAL): add code to save ACLOCAL_FLAGS - - * src/frames.c (meta_frames_expose_event): max dither - - * src/testgradient.c (render_simple): change dither mode to MAX - to avoid banding - - * src/theme.c: lose the gradient cache, and put in some initial - data types for the theme format - -2002-01-07 Havoc Pennington <hp@redhat.com> - - * src/frames.c (meta_frames_expose_event): make gradient a bit - more subtle (don't go to the full background, but to a blend of - selection and background; put lighter color on top) - -2002-01-06 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_notify_focus): rearrange code a bit to - make it clear that has_focus flag always follows - display->focus_window - -2002-01-06 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_notify_focus): put in attempted fix - for the GTK 1.2 plug/socket screwup, now that my fixed debug spew - reveals what's actually happening. ;-) - - * src/gradient.c (meta_gradient_description_new): object - to store gradient descriptions - - * src/window.c (meta_window_notify_focus): fix the debug spew - that was confusing me - - * src/wm-tester/focus-window.c: add little program to focus - a window ID - -2002-01-06 Havoc Pennington <hp@pobox.com> - - * src/theme.c (meta_theme_get_gradient): change to use spiffy - gradient code. - - * src/gradient.c: copy lovely gradient code from WindowMaker, - as usual Dan and Alfredo have very nice code - -2002-01-06 Fatih Demir <kabalak@gtranslator.org> - - * configure.in: Added "tr" to the languages list. - -2002-01-05 Havoc Pennington <hp@pobox.com> - - * src/frames.c (meta_frames_expose_event): draw titlebar highlight - with snazzy gradient that needs some tweaking to be less - dumb-looking - - * src/theme.c: replace old theme.[hc] contents with newer stuff - that doesn't do anything - -2002-01-05 Havoc Pennington <hp@pobox.com> - - GTK 1.2 plug/socket clients still broken, don't know why. - - * src/screen.c (meta_screen_new): select focus change on root - window, for debugging - - * src/display.c (event_callback): when unfocusing, use - no_focus_window to hold the focus - - * src/display.h (struct _MetaDisplay): have a no_focus_window to - hold the focus when we don't want to have anything focused. - Then we can avoid confusing focusing-the-frame stuff. - - * src/window.c (meta_window_notify_focus): improve some debug spew - (meta_window_notify_focus): add hack from WindowMaker to ignore - focus in events with detail > NotifyNonlinearVirtual - -2002-01-04 Havoc Pennington <hp@pobox.com> - - * src/display.c (event_callback): don't lower docks when a grab - causes them to get LeaveNotify - -2002-01-04 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_free): set event mask on root window - to 0 so other window managers (such as ourselves restarting) can - start up; addresses race condition on restart where the old WM - still had RedirectMask when the new WM was trying to start up. - - * src/display.c (meta_display_close): free each screen - - * src/window.c (meta_window_show): always focus new windows in - click-to-focus mode - -2002-01-03 Havoc Pennington <hp@pobox.com> - - * src/window.c: use meta_XFree not XFree - - * src/display.h (meta_XFree): add null-safe XFree - - * src/util.c (meta_warning): have message prefix indicate that - it's a warning - (meta_fatal): indicate it's an error - - * src/window.c (update_sm_hints): clean up using - meta_prop_get_latin1_string - (update_role): ditto - (read_client_leader): clean up using meta_prop_get_window - (update_net_wm_type): clean up using meta_prop_get_cardinal - (update_initial_workspace): ditto - (update_net_wm_type): clean up using meta_prop_get_atom_list - (read_rgb_icon): get result from XGetWindowProperty return value - not from error trap - (update_kwm_icon): ditto - (meta_window_new): fix to read WM_STATE correctly - -2002-01-03 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_net_wm_state): clean up using - meta_prop_get_atom_list - (update_mwm_hints): clean up using meta_prop_get_motif_hints - - * src/Makefile.am (metacity_SOURCES): add xprops.[hc] - - * src/xprops.c: new file with convenience functions for X - properties - -2002-01-03 Havoc Pennington <hp@pobox.com> - - * src/workspace.c (meta_workspace_activate): focus top window when - switching to a new workspace - - * src/util.c (meta_topic): start putting verbose output in - categories - - * src/window.c (meta_window_shade): focus frame after we queue - the calc_showing so the maps/unmaps have already happened. - - * src/display.c (meta_display_get_current_time): add the "get time - of current event" function and call it occasionally. - - * src/window.c (meta_window_free): if we have focus, call - meta_screen_focus_top_window(). - (meta_window_minimize): ditto - (meta_window_delete): ditto - - * src/screen.c (meta_screen_ensure_tab_popup): fix memory leak - - didn't free tab list - (meta_screen_focus_top_window): new function to use when we unmap - or unmanage a focused window - - * src/stack.c (meta_stack_get_default_focus_window): function used - in meta_screen_focus_top_window - -2001-12-21 Havoc Pennington <hp@redhat.com> - - * src/frame.c (meta_window_ensure_frame): add a server grab - here since we were failing to have one when calling the function - -2001-12-27 Duarte Loreto <happyguy_pt@hotmail.com> - - * configure.in: Added portuguese to ALL_LINGUAS - -2001-12-16 Kjartan Maraas <kmaraas@gnome.org> - - * configure.in: Added "no" to ALL_LINGUAS. - -2001-12-11 Stanislav Visnovsky <visnovsky@nenya.ms.mff.cuni.cz> - - * configure.in: Added "sk" to ALL_LINGUAS. - -2001-12-10 Havoc Pennington <hp@pobox.com> - - Rework the click-client-area-to-focus support to use synchronous - grabs, avoids a big mess, lets us pass through click when - required (for dock/desktop). Disadvantage is all left-button - clicks now require window manager approval. ;-) - - * src/display.c (event_callback): don't focus dock/desktop when - the mouse enters them; require a click. - (meta_change_button_grab): allow sync grabs - (meta_display_grab_unfocused_window_buttons): establish a - synchronous grab and maintain it all the time, rename to - meta_display_grab_focus_window_button - - * src/window.c: change to reflect display.c - -2001-12-10 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_update_unfocused_button_grabs): oops, - unbreak this _again_ - reported by Josh Barrow - -2001-12-10 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_update_unfocused_button_grabs): don't - allow grab on docks/desktop for now; needs fixing later to - do the grab, but pass thru click, so we can focus those windows. - And in fact we need to do that even in sloppy mode. - -2001-12-10 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_foreach_window): fix broken - "tmp = tmp->data" - - Implement do-not-pass-thru-click for click-to-focus mode. - - * src/screen.c (update_focus_mode): when focus mode changes, - update all the window grabs - - * src/display.c (meta_display_grab_unfocused_window_buttons): - implement grabbing button 1 on client area of unfocused - click-to-focus windows - - * src/window.c (meta_window_update_unfocused_button_grabs): update - whether we're grabbing unmodified button 1 on client area - according to focus state and focus mode - (meta_window_new): start out with proper grab state - -2001-12-10 Havoc Pennington <hp@pobox.com> - - * src/menu.c (meta_window_menu_new): don't do mnemonics for - workspaces above 9 - -2001-12-10 Havoc Pennington <hp@pobox.com> - - * src/screen.c (meta_screen_new): oops, remove extra workspace - creation, and update to current pref. - -2001-12-09 Havoc Pennington <hp@pobox.com> - - * src/workspace.c (meta_workspace_free): update number of - workspaces hint - - * src/screen.c (update_num_workspaces): implement number of - workspaces setting - - * src/window.c (meta_window_configure_request): honor configure - requests on windows of type NORMAL, but still be mean to those of - type DIALOG - - * src/main.c (main): add more log domains to those we set a log - handler for, and only set warnings fatal in debug mode - - * src/metacity.schemas: add number of workspaces setting - -2001-12-09 Havoc Pennington <hp@pobox.com> - - * src/display.c (event_callback): in click-to-focus mode don't - focus on enter notify. Implement unfocusing on LeaveNotify in - mouse focus mode. Click to focus just ends up working if we - do nothing on enter/leave, because of the way things already - worked. Except I need to add some relatively complex hack to - allow clicking on client area, right now you have to click - on the frame. - -2001-12-09 Havoc Pennington <hp@pobox.com> - - * src/main.c (main): move SM init a bit later in the process, and - init prefs - - * src/session.c: fix no SM case (though I hardly know why I'm - bothering) - - * src/main.c (main): call bindtextdomain - - * src/util.h (_): actually call gettext - - * configure.in: put in AM_GLIB_GNU_GETTEXT and gconf stuff - - * src/prefs.c: Preferences - this marks the beginning of our doom. - None of them are actually implemented yet, but we monitor - some stuff from gconf. - -2001-12-07 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_unminimize): when unminimizing an app, - if we're in "show desktop" (all windows minimized) mode, leave - show desktop mode. Will occasionally be a bit weird, but allows - people to recover via task list if they accidentally do the show - desktop thing, and don't know what's going on. - -2001-12-06 Havoc Pennington <hp@redhat.com> - - * src/ui.c (meta_text_property_to_utf8): fix gdkatom/xatom screwup - - gee, I should read my warnings - -2001-12-03 Laszlo Peter <laca@ireland.sun.com> - - * src/frames.c: add a dummy element to the enum so - the signals array is not empty. (breaks the build with Forte C) - - * src/window.c: s/__FUNCTION__/G_GNUC_FUNCTION/ - -2001-11-27 Havoc Pennington <hp@pobox.com> - - * src/window.c (constrain_position): change so that window can be - offscreen to the bottom or the right, as long as a small top-left - corner of the window remains onscreen. However, windows still - can't go off the left or top. - -2001-11-26 Havoc Pennington <hp@redhat.com> - - * src/window.c (window_query_root_pointer): add error trap - -2001-11-27 Jesus Bravo Alvarez <jba@pobox.com> - - * configure.in: Added gl (Galician) to ALL_LINGUAS. - -Tue Nov 20 18:49:16 2001 Owen Taylor <otaylor@redhat.com> - - * configure.in (found_sm): Add some additional quoting to - make it work with autoconf-2.5x. - -2001-11-02 Laszlo Peter <laca@ireland.sun.com> - - * src/window.c (update_sm_hints): protect meta_verbose from - a NULL pointer. - -2001-10-29 Havoc Pennington <hp@pobox.com> - - * configure.in: bump version - -2001-10-29 Havoc Pennington <hp@pobox.com> - - * src/window.c (idle_calc_showing): handle queue/unqueue of - calc showings as we are iterating over the pending list - (meta_window_show): focus placed transients in here instead - of in meta_window_place - now it should actually work, yay - - * src/place.c (meta_window_place): remove focusing of transient - child from here; this was really broken - -2001-10-29 Yuriy Syrota <rasta@renome.rovno.ua> - - * configure.in: Added "uk" to ALL_LINGUAS. - -2001-10-29 Havoc Pennington <hp@pobox.com> - - * README: note exciting new unminimize feature for the tab popup - - * src/keybindings.c (process_tab_grab): use meta_window_activate() - when choosing a window with tab popup, this should deiconify it - - * src/window.c (meta_window_client_message): use - meta_window_activate for _NET_ACTIVE_WINDOW message - (meta_window_activate): new function to raise/focus/unminimize - (meta_window_flush_calc_showing): new function - (meta_window_focus): force a calc showing on focus, so that we can - focus the window if appropriate (it must be mapped) - -2001-10-26 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_grab_window_buttons): fix for - ignoring NumLock on Alt-windowclick (previous NumLock fix - was only for key grabs not button grabs) - -2001-10-25 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_new): set the current workspace hint - -2001-10-25 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_visible_on_workspace): - I was using meta_workspace_contains_window() in a number of - places where on_all_workspaces should also have been considered, - thus this new function. Fixes bugs such as pinned windows - not appearing in the tab order. - (meta_window_client_message): use meta_window_visible_on_workspace - - * src/stack.c (find_tab_forward): ditto - (find_tab_backward): ditto - (meta_stack_get_tab_next): ditto - (meta_stack_get_tab_list): ditto - - * src/place.c (get_windows_on_same_workspace): ditto - - * src/keybindings.c (handle_focus_previous): ditto - (handle_focus_previous): ditto - -2001-10-24 Havoc Pennington <hp@pobox.com> - - * src/frames.c (meta_frames_expose_event): use bg/fg not base/text - for the window title area. - -2001-10-24 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_new): support initial - on-all-workspaces setting - -2001-10-22 Havoc Pennington <hp@pobox.com> - - * src/stack.c (meta_stack_sync_to_server): fix to keep desktop - window from appearing on top of everything else, among other stack - bugs. Untested. - -2001-10-15 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_new): use queried attributes to check - whether window should be initially maximized, rather than window - rect - -2001-10-15 Havoc Pennington <hp@pobox.com> - - * src/main.c (meta_restart): add a restart feature, for debugging - - * src/tools/metacity-restart.c: little utility program to trigger - the restart - -2001-10-14 Havoc Pennington <hp@pobox.com> - - * src/frames.c (meta_frames_button_press_event): raise/focus - windows on left-click, seem to have broken that yesterday - - * src/keybindings.c, src/display.c, src/window.c: add keybinding - to show/hide all normal windows (so you can see the desktop). - Currently Ctrl+Alt+D, which I don't like, but yay. - -2001-10-14 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_new): take a window mapped at - fullscreen size/pos to desire maximization; once I add a - fullscreen state, will change to copy kwin and take this mapping - as a desire for fullscreen, but for now testing with maximization. - - * src/window.h: remove fullscreen window type, now proposing it - as a window state instead. - -2001-10-14 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_maximize): always raise windows on - maximize - (meta_window_client_message): when activating a window, move - it to current workspace, instead of moving user to the - window's workspace. - -2001-10-14 HÃ�©ctor GarcÃ�a Ã�Âlvarez <hector@scouts-es.org> - - * configure.in: Added "es" to ALL_LINGUAS for Spanish translation. - -2001-10-14 Havoc Pennington <hp@pobox.com> - - * src/display.c (event_callback): only handle events here if - the modmask from our button grab is active. i.e. only the - Alt-click is handled here. - - * src/frames.c: add check for whether button presses are in the - frame client area before handling them, so we don't weirdly let - you move a frame by clicking in its client area if the client - hasn't selected button press events. - -2001-10-13 Havoc Pennington <hp@pobox.com> - - * src/stack.c (meta_stack_sync_to_server): set last window before - setting newp, so we don't get the current window as the last - window and screw everything up - (IN_TAB_CHAIN): use type not layer to decide if a window is - in the tab chain, keeps panel out of alt-tab choices - -2001-10-13 Havoc Pennington <hp@redhat.com> - - * configure.in: add bad hack to work with GTK 1.3.9.90 RPMs from - gnomehide for now - - * src/ui.c: another piece of bad hack in here - -2001-10-13 Havoc Pennington <hp@redhat.com> - - * configure.in: bump version - -2001-10-13 Havoc Pennington <hp@pobox.com> - - * src/session.c (meta_session_init): hmm, fix build - -2001-10-12 Havoc Pennington <hp@pobox.com> - - * src/session.c (meta_session_init): set the session manager - priority so we start up before other apps. - -2001-10-12 Mikael Hallendal <micke@codefactory.se> - - * src/ui.c (meta_ui_get_default_window_icon): use - gdk_pixbuf_new_from_inline - (meta_ui_get_default_mini_icon): use - gdk_pixbuf_new_from_inline - -2001-10-11 Christian Rose <menthos@menthos.com> - - * configure.in: Added "sv" to ALL_LINGUAS. - -2001-10-10 Havoc Pennington <hp@pobox.com> - - * src/stack.c (meta_stack_free): fix mem leak of the MetaStack - object - (meta_stack_sync_to_server): try to avoid the restack-flicker - thing - -2001-10-07 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_update_active_window_hint): - set _NET_ACTIVE_WINDOW hint - - * src/window.c (meta_window_client_message): support - _NET_ACTIVE_WINDOW client message - -2001-10-07 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_client_message): don't allow - shade/maximize/minimize for windows that don't support those - operations. (minimizing the panel = bad) - -2001-10-04 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c (meta_change_keygrab): add code to grab all - modifier combinations, so keybindings work with NumLock etc. - - * src/menu.c (meta_window_menu_new): remove newlines from menu - items - -2001-09-27 Havoc Pennington <hp@pobox.com> - - * src/session.c (save_state): when encoding text for session file, - escape XML entities - -2001-09-21 Alex Graveley <alex@ximian.com> - - * src/Makefile.am (metacity_SOURCES): Add inlinepixbufs.h so - that it gets generated. - - * src/frames.c (meta_frames_style_set): Update for new opaque - PangoFontMetrics. - -2001-09-17 Havoc Pennington <hp@pobox.com> - - * src/ui.c (meta_ui_init): add hackaround for the warning about - gtk-menu-bar-accel - -2001-09-17 Havoc Pennington <hp@pobox.com> - - * src/ui.c (meta_ui_get_default_mini_icon): - (meta_ui_get_default_window_icon): ref the returned icon, oops. - - * src/main.c (main): get the GLib warning/error output into - the metacity logfile, set warnings to be always fatal - - * configure.in: bump version to 2.3.13 - - * src/window.c (get_text_property): hrm, fix bug where we didn't - check errors on XGetTextProperty - -2001-09-17 Havoc Pennington <hp@pobox.com> - - * src/Makefile.am (VARIABLES): fix srcdir != builddir glitch - -2001-09-17 Havoc Pennington <hp@pobox.com> - - * src/ui.c: use the inline image data for default icon - - * src/common.h (META_MINI_ICON_HEIGHT): move icon size defines - here - - * src/Makefile.am: Create an inlinepixbufs.h header with inline - images - -2001-09-16 Havoc Pennington <hp@pobox.com> - - * src/session.c (process_ice_messages): disconnect this callback - on error - -2001-09-16 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_lower): new function - - * configure.in: bump version to 2.3.8 - - * src/display.c (event_callback): raise dock on enter notify, - lower it on leave notify (need to refine this behavior) - - * src/stack.c (compute_layer): experiment with putting the panel - in the normal layer, and raising it on mouseover - -2001-09-15 Havoc Pennington <hp@pobox.com> - - * src/window.c: add support for a mini icon in the titlebar - (update_icon): re-enable support for _NET_WM_ICON - - * src/session.c (save_state): add an ferror check when writing - session file - -2001-09-11 Havoc Pennington <hp@pobox.com> - - * src/main.c (usage): exit with error code on usage() (kind of - wrong for --help, but oh well). - -2001-09-11 Havoc Pennington <hp@pobox.com> - - * src/window.c: fix up handling of text properties, so we - get UTF8_STRING as that type and not as text list, and so - we properly convert from text list to UTF-8 - -2001-09-10 Havoc Pennington <hp@pobox.com> - - * src/menu.c (meta_window_menu_new): icon for unmaximize - - * src/ui.c (meta_ui_init): fix call to XDisplayName - - * src/util.c: add missing header - - * src/frames.c: draw an unmaximize control if already maximized - -2001-09-10 Havoc Pennington <hp@pobox.com> - - * src/window.c: Don't separate user_has_moved/user_has_resized, - fixes bug in east-resizing Emacs, among other things - - * src/frame.c (meta_frame_sync_to_window): return immediately if - nothing to do - - * src/util.c (ensure_logfile): replace rather than truncate old - logfiles - -2001-09-08 Havoc Pennington <hp@pobox.com> - - * src/ui.c (meta_ui_init): don't use gdk_display_name - - * src/frame.c (meta_window_ensure_frame): create frame - with screen default visual, rather than client window visual; - for DRI games, the client window visual was not allowed to be - a child of another window with the same visual, apparently. - Anyhow now we copy twm, etc. so it must be correct. - - * src/place.c (meta_window_place): if a transient is placed and - its parent has focus, focus the transient. - -2001-09-06 Havoc Pennington <hp@pobox.com> - - * configure.in: bump version 2.3.5, require newer GTK release - -2001-09-04 Havoc Pennington <hp@pobox.com> - - * src/wm-tester/Makefile.am (noinst_PROGRAMS): make test apps - noinst - - * src/metacity.desktop: for the capplet - - * src/Makefile.am: add .desktop file - -2001-09-01 Havoc Pennington <hp@pobox.com> - - * src/errors.c: clean up the code, and replace GDK X error handler - with one that chains up to GDK but first logs the error to logfile. - -2001-08-31 Havoc Pennington <hp@pobox.com> - - * src/tabpopup.c (meta_ui_tab_popup_new): fix args to - gtk_alignment_new() - -2001-08-29 Havoc Pennington <hp@pobox.com> - - * src/display.c (event_callback): avoid focusing a window on tab - popup popdown - - * src/screen.c (meta_screen_ensure_tab_popup): compute frame - outline size here - -2001-08-29 Havoc Pennington <hp@redhat.com> - - * src/tabpopup.c: Switch back to outline. - -2001-08-29 Havoc Pennington <hp@pobox.com> - - * src/tabpopup.c: experiment with window-cover-with-icon - instead of just the outline; can't decide. - -2001-08-29 Havoc Pennington <hp@pobox.com> - - * src/tabpopup.c: add crackrock window-outlining feature - - * src/session.c (window_type_to_string): handle fullscreen - -2001-08-29 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_open): wrong atom name - - _NET_SUPPORTED not _NET_WM_SUPPORTED - - * src/window.c (meta_window_configure_request): geez, why were we - honoring configure requests for width/height for normal windows. - Denied! - (meta_window_client_message): _NET_WM_MOVERESIZE support, sort of - (doesn't quite work, acts like owner_events = true?) - - * src/display.c: add _NET_WM_MOVERESIZE atom - -2001-08-28 Havoc Pennington <hp@pobox.com> - - Unbreak tab popup a bit. - - * src/stack.c (meta_stack_get_tab_list): add workspace argument - (meta_stack_get_tab_next): add workspace argument - - * src/window.c: implement recording of the last user-initiated - window position, so we can magically handle moving panels around - really nicely. - - * src/wm-tester/main.c (set_up_icon_windows): fix to use new GTK - API - -2001-08-24 Havoc Pennington <hp@pobox.com> - - * src/window.c (constrain_position): force fullscreen windows to - be at 0,0 - - * src/ui.c: use NULL colormap to get bitmaps, requires - very latest GTK from CVS or it will spew warnings - and not work. - - * src/window.c (constrain_size): disallow larger than screen in - all cases, even if user has performed a resize operation. - (constrain_position): keep window boxed onscreen. - - * src/keybindings.c (meta_display_process_key_event): revert an - earlier change that disabled global keybindings when a grab is in - effect; instead, only disable global keybindings if a _keyboard_ - grab is in effect. The earlier change was just a broken - workaround, the problems it fixed should have been solved by the - addition of XGrabKeyboard() on the metacity keyboard grabs. - - This should fix the problem with - pick-up-window-and-move-to-another-desktop. - -2001-08-23 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_icon): attempt to use the mask as well as - the pixmap. Probably doesn't work so well. - - * src/tabpopup.c: make this look a little nicer - -2001-08-22 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_mwm_hints): all the MWM flag tests were - backward - -2001-08-22 Havoc Pennington <hp@pobox.com> - - * src/window.c (update_icon): half-ass implementation of - getting pixmap icons (WM_NORMAL_HINTS and KWM_WIN_ICON). - Ignores mask for now, with possibly ugly results for - some apps. - (read_rgb_icon): fixage - -2001-08-19 Havoc Pennington <hp@pobox.com> - - * src/window.c: add a "fullscreen" semantic type; if a window - requests the screen size exactly, and is undecorated, and is not a - desktop window, we consider it a fullscreen window and keep it on - top. - - Totally untested. - -2001-08-19 Havoc Pennington <hp@pobox.com> - - * src/screen.c (set_supported_hint): we support _NET_WM_ICON - - * src/wm-tester/main.c: add stuff to test _NET_WM_ICON - (but it doesn't work, so it isn't tested yet) - - * src/window.c (update_icon): read _NET_WM_ICON - - * src/screen.c (meta_screen_new): set the WM_ICON_SIZE hint - - * src/tabpopup.c (meta_ui_tab_popup_select): remove assertion - - * src/window.c (meta_window_get_icon_geometry): fix obscure - memleak - -2001-08-19 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_grab_window_buttons): remove XSync, - error traps already do that - (meta_display_grab_window_buttons): implement - - * src/keybindings.c: - src/display.c: wire up the tab window, it rulez! - -2001-08-19 Havoc Pennington <hp@pobox.com> - - * src/tabpopup.c: add prototype thingy to display windows we're - cycling through with tab. Not wired up to keybindings yet. - -2001-08-18 Havoc Pennington <hp@pobox.com> - - * src/effects.c (meta_effects_draw_box_animation): put an XFlush() - right after starting things moving - -2001-08-18 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_configure_request): - (meta_window_move_resize_internal): Make a half-hearted - not-very-tested attempt to handle window resizes correctly with - respect to window gravity. - -2001-08-18 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_get_gravity_position): hrm, I fixed - this wrong the other day. Fixes static gravity when moving - windows. - -2001-08-18 Havoc Pennington <hp@pobox.com> - - * src/ui.c (meta_image_window_set_position): also set the current - size. Lame hack of the day. - - * src/effects.c (effects_draw_box_animation_timeout): use the - delay exposes feature to avoid the screen dirt - - * src/ui.c - (meta_ui_push_delay_exposes): - (meta_ui_pop_delay_exposes): feature to let us delay redraws until - after we do server-grabbed draw-on-inferiors effects - -2001-08-17 Havoc Pennington <hp@redhat.com> - - * src/window.c (meta_window_get_gravity_position): fix for - StaticGravity - -2001-08-09 Havoc Pennington <hp@pobox.com> - - * src/window.c (meta_window_configure_request): Honor USPosition - even post-map. I know I'll regret this. - -2001-08-07 Havoc Pennington <hp@pobox.com> - - * src/display.c (meta_display_open): set _NET_WM_NAME - hint as a UTF8_STRING not STRING. Patch from Anders. - -2001-08-06 Havoc Pennington <hp@redhat.com> - - * src/effects.c: disable opaque animations by default, current - implementation suXors. - -2001-08-06 Havoc Pennington <hp@pobox.com> - - * src/effects.c (meta_effects_draw_box_animation): Get start - time after we do the pixbuf from drawable, so we don't count - time spent getting pixbuf from drawable in the animation time. - -2001-08-06 Havoc Pennington <hp@pobox.com> - - * src/effects.c: add opaque minimize/shade feature. The wireframe - seemed kind of confusing and unclear from a UI standpoint. - I know, I know. The bloat begins here. - - Also, we don't need to grab the server during opaque min/shade, - which has some nice implications. - - * src/ui.c: Add features to render a window with an image in it, - and also wrap pixbuf_from_drawable - - * src/effects.c (meta_effects_draw_box_animation): - modify to be smoother (at least theoretically) by - syncing to current time and "dropping frames" - as appropriate. - - * src/window.c (meta_window_shade): draw animation - for shading too - -2001-08-05 Anders Carlsson <andersca@gnu.org> - - * src/display.h, src/display.c: Add _NET_WM_ICON_GEOMETRY atom. - - * src/window.c (meta_window_calc_showing): See if the window has - an icon geometry and show a morphing animation from the window's - coordinates to the icon's coordinates. - (meta_window_get_icon_geometry): New function that fetches a - window's icon geometry. - - * src/Makefile.am: Add effects.[ch]. - - * src/effects.c: New file with cool effects. - -2001-08-03 Havoc Pennington <hp@pobox.com> - - * src/keybindings.c: Add Alt + left/right arrow to - move between workspaces. - - * src/screen.c (set_wm_check_hint): put property pointing back to - itself on the _WIN_SUPPORTING_WM_CHECK window. - -2001-08-03 Havoc Pennington <hp@pobox.com> - - * src/display.c (event_callback): push error trap around configure - of withdrawn window, fixes a crash caused by rapidly - creating/destroying a window. - - * src/window.c (recalc_window_features): don't allow shading - undecorated windows. - - * src/wm-tester/main.c: add a program to torture window managers. - -2001-08-01 Havoc Pennington <hp@pobox.com> - - * src/window.c (recalc_window_features): if a window isn't - resizeable, turn off maximize function. If min size is equal to - max size, turn off resize function. - diff --git a/Doxyfile b/Doxyfile deleted file mode 100644 index a8a7541..0000000 --- a/Doxyfile +++ /dev/null @@ -1,1297 +0,0 @@ -# Doxyfile 1.5.3 - -# This is the doxyfile for Metacity. - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file that -# follow. The default is UTF-8 which is also the encoding used for all text before -# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into -# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of -# possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = metacity - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -# Do not enter a setting here; it will only get out of date. -PROJECT_NUMBER = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = doc - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, -# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, -# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, -# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to -# include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = YES - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be extracted -# and appear in the documentation as a namespace called 'anonymous_namespace{file}', -# where file will be replaced with the base name of the file that contains the anonymous -# namespace. By default anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command <command> <input-file>, where <command> is the value of -# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = YES - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = src - -# This tag can be used to specify the character encoding of the source files that -# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default -# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. -# See http://www.gnu.org/software/libiconv for the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py - -FILE_PATTERNS = *.c *.h - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the output. -# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, -# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command <filter> <input-file>, where <filter> -# is the value of the INPUT_FILTER tag, and <input-file> is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH -# then you must also enable this option. If you don't then doxygen will produce -# a warning and turn it on anyway - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = YES - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = NO - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to -# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to -# specify the directory where the mscgen tool resides. If left empty the tool is assumed to -# be found in the default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a caller dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the number -# of direct children of the root node in a graph is already larger than -# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/HACKING b/HACKING deleted file mode 100644 index 763bc88..0000000 --- a/HACKING +++ /dev/null @@ -1,298 +0,0 @@ -Intro... - -Window managers have a few ways in which they are significantly different -from other applications. This file, combined with the code overview in -doc/code-overview.txt, should hopefully provide a series of relatively -quick pointers (hopefully only a few minutes each) to some of the places -one can look to orient themselves and get started. Some of this will be -general to window managers on X, much will be specific to Metacity, and -there's probably some information that's common to programs in general but -is nonetheless useful. - -Overview - Administrative issues - Minimal Building/Testing Environment - Relevant standards and X properties - Debugging and testing - Debugging logs - Adding information to the log - Valgrind - Testing Utilities - Technical gotchas to keep in mind - Other important reading - Extra reading - Ideas for tasks to work on - - -Administrative issues - Don't commit substantive code in here without asking hp@redhat.com. - Adding translations, no-brainer typo fixes, etc. is fine. - - The code could use cleanup in a lot of places, feel free to do so. - - See http://developer.gnome.org/dotplan/for_maintainers.html for - information on how to make a release. The only difference from those - instructions is that the minor version number of a Metacity release - should always be a number from the Fibonacci sequence. - -Minimal Building/Testing Environment - You do not need to _install_ a development version of Metacity to - build, run and test it; you can run it from some temporary - directory. Also, you do not need to build all of Gnome in order to - build a development version of Metacity -- odds are, you may be able - to build metacity from CVS without building any other modules. - - As long as you have gtk+ >= 3.0 and GIO >= 2.25.10 with your distro - (gtk+ >= 2.6 if you manually revert the change from bug 348633), you - should be able to install your distro's development packages - (e.g. gtk2-devel, glib-devel, startup-notification-devel on - Fedora; also, remember to install the gnome-common package which is - needed for building cvs versions of Gnome modules like Metacity) as - well as the standard development tools (gcc, autoconf, automake, - pkg-config, intltool, and libtool) and be ready to build and test - Metacity. Steps to do so: - - $ svn checkout http://svn.gnome.org/svn/metacity/trunk metacity - $ cd metacity - $ ./autogen.sh --prefix /usr - $ make - $ ./src/metacity --replace - - Again, note that you do not need to run 'make install'. - -Relevant standards and X properties - There are two documents that describe some basics about how window - managers should behave: the ICCCM (Inter-Client Communication Conventions - Manual) and EWMH (Extended Window Manager Hints). You can find these at - the following locations: - ICCCM - http://tronche.com/gui/x/icccm/ - EWMH - :pserver:anoncvs@pdx.freedesktop.org:/cvs - The ICCCM is usually available in RPM or DEB format as well. There is - actually an online version of the EWMH, but it is almost always woefully - out of date. Just get it from cvs with these commands (the backslash - means include the stuff from the next line): - cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions login - cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions \ - checkout wm-spec - - DO NOT GO AND READ THOSE THINGS. THEY ARE REALLY, REALLY BORING. - - If you do, you'll probably end up catching up on your sleep instead of - hacking on Metacity. ;-) Instead, just look at the table of contents and - glance at a page or two to get an idea of what's in there. Then only - refer to it if you see something weird in the code and you don't know - what it is but has some funny looking name like you see in one of those - two documents. - - You can refer to the COMPLIANCE file for additional information on these - specifications and Metacity's compliance therewith. - - One of the major things those documents cover that are useful to learn - about immediately are X properties. The right way to learn about those, - though, is through hand on experimentation with the xprop command (and - then look up things you find from xprop in those two manuals if you're - curious enough). First, try running - xprop - in a terminal and click on one of the windows on your screen. That gives - you the x properties for that window. Look through them and get a basic - idea of what's there for kicks. Note that you can get rid of some of the - verboseness by grepping out the _NET_WM_ICON stuff, i.e. - xprop | grep -v _NET_WM_ICON - Next, try running - xprop -root - in a terminal. There's all the properties of the root window (which you - can think of as the "main" Xserver window). You can also manually - specify individual windows that you want the properties of with - xprop -id <id> - if you know the id of the window in question. You can get the id of a - given window by either running xwininfo, e.g. - xwininfo | grep "Window id" | cut -f 4 -d ' ' - or by looking at the _NET_CLIENT_STACKING property of the root - window. Finally, it can also be useful to add "-spy" (without the - quotes) to the xprop command to get it to continually monitor that - window and report any changes to you. - -Debugging information - Trying to run a window manager under a typical debugger, such as gdb, - unfortunately just doesn't work very well. So, we have to resort to - other methods. - - Debugging logs - - First, note that you can start a new version of metacity to replace the - existing one by running - metacity --replace - (which also comes in handy in the form "./src/metacity --replace" when - trying to quickly test a small change while hacking on metacity without - doing a full "make install", though I'm going off topic...) This will - allow you to see any warnings printed at the terminal. Sometimes it's - useful to have these directed to a logfile instead, which you can do by - running - METACITY_USE_LOGFILE=1 metacity --replace - The logfile it uses will be printed in the terminal. Sometimes, it's - useful to get more information than just warnings. You can set - METACITY_VERBOSE to do that, like so: - METACITY_VERBOSE=1 METACITY_USE_LOGFILE=1 metacity --replace - (note that METACITY_VERBOSE=1 can be problematic without - METACITY_USE_LOGFILE=1; avoid it unless running in from something that - won't be managed by the new Metacity--see bug 305091 for more details). - There are also other flags, such as METACITY_DEBUG, most of which I - haven't tried and don't know what they do. Go to the source code - directory and run - grep "METACITY_" * | grep getenv - to find out what the other ones are. - - Adding information to the log - - Since we can't single step with a debugger, we often have to fall back to - the primitive method of getting information we want to know: adding - "print" statements. Metacity has a fairly structured way to do this, - using the functions meta_warning, meta_topic, and meta_verbose. All - three have the same basic format as printf, except that meta_topic also - takes a leading enumeration parameter to specify the type of message - being shown (makes it easier for grepping in a verbose log). You'll find - tons of examples in the source code if you need them; just do a quick - grep or look in most any file. Note that meta_topic and meta_verbose - messages only appear if verbosity is turned on. I tend to frequently add - temporary meta_warning statements (or switch meta_topic or meta_verbose - ones to meta_warning ones) and then undo the changes once I've learned - the info that I needed. - - There is also a meta_print_backtrace (which again is only active if - verbosity is turned on) that can also be useful if you want to learn how - a particular line of code gets called. And, of course, there's always - g_assert if you want to make sure some section isn't executed (or isn't - executed under certain conditions). - - Valgrind - - Valgrind is awesome for finding memory leaks or corruption and - uninitialized variables. But I also tend to use it in a non-traditional - way as a partial substitute for a normal debugger: it can provide me with - a stack trace of where metacity is crashing if I made a change that - caused it to do so, which is one of the major uses of debuggers. (And, - what makes it cooler than a debugger is that there will also often be - warnings pinpointing the cause of the crash from either some kind of - simple memory corruption or an uninitialized variable). Sometimes, when - I merely want to know what is calling a particular function I'll just - throw in an "int i; printf("%d\n", i);" just because valgrind will give - me a full stacktrace whenever it sees that uninitialized variable being - used (yes, I could use meta_print_backtrace, but that means I have to - turn verbosity on). - - To run metacity under valgrind, use options typical for any Gnome - program, such as - valgrind --log-file=metacity.log --tool=memcheck --num-callers=48 \ - --leak-check=yes --leak-resolution=high --show-reachable=yes \ - ./src/metacity --replace - where, again, the backslashes mean to join all the stuff on the following - line with the previous one. - - However, there is a downside. Things run a little bit slowly, and it - appears that you'll need about 1.5GB of ram, which unfortunately prevents - most people from trying this. - - Testing Utilities - - src/run-metacity.sh - The script src/run-metacity.sh is useful to hack on the window manager. - It runs metacity in an Xnest. e.g.: - CLIENTS=3 ./run-metacity.sh - or - DEBUG=memprof ./run-metacity.sh - or - DEBUG_TEST=1 ./run-metacity-sh - or whatever. - - metacity-message - The tool metacity-message can be used as follows: - metacity-message reload-theme - metacity-message restart - metacity-message enable-keybindings - metacity-message disable-keybindings - The first of these is useful for testing themes, the second is just - another way (besides the --restart flag to metacity itself) of - restarting metacity, and the third is useful for testing Metacity when - running it under an Xnest (typically, the Metacity under the Xnest - wouldn't get keybinding notifications--making keyboard navigation not - work--but if you disable the keybindings for the global Metacity then - the Metacity under the Xnest can then get those keybinding notifications). - - metacity-window-demo - metacity-window-demo is good for trying behavior of various kinds - of window without launching a full desktop. - -Technical gotchas to keep in mind - Files that include gdk.h or gtk.h are not supposed to include - display.h or window.h or other core files. Files in the core - (display.[hc], window.[hc]) are not supposed to include gdk.h or - gtk.h. Reasons: - - "Basically you don't want GDK most of the time. It adds - abstractions that cause problems, because they aren't designed to - be used in a WM where we do weird stuff (display grabs, and just - being the WM). At best GDK adds inefficiency, at worst it breaks - things in weird ways where you have to be a GDK guru to figure - them out. Owen also told me that they didn't want to start adding - a lot of hacks to GDK to let a WM use it; we both agreed back in - the mists of time that metacity would only use it for the "UI" - bits as it does. - - Having the split in the source code contains and makes very clear - the interface between the WM and GDK/GTK. This keeps people from - introducing extra GDK/GTK usage when it isn't needed or - appropriate. Also, it speeds up the compilation a bit, though this - was perhaps more relevant 5 years ago than it is now. - - There was also a very old worry that the GDK stuff might have to - be in a separate process to work right; that turned out to be - untrue. Though who knows what issues the CM will introduce." - - Remember that strings stored in X properties are not in UTF-8, and they - have to end up in UTF-8 before we try putting them through Pango. - - If you make any X request involving a client window, you have to - meta_error_trap_push() around the call; this is not necessary for X - requests on the frame windows. - - Remember that not all windows have frames, and window->frame can be NULL. - -Other important reading & where to get started - Extra reading - - There are some other important things to read to get oriented as well. - These are: - http://pobox.com/~hp/features.html - rationales.txt - doc/code-overview.txt - - It pays to read http://pobox.com/~hp/features.html in order - to understand the philosophy of Metacity. - - The rationales.txt file has two things: (1) a list of design choices with - links in the form of bugzilla bugs that discuss the issue, and (2) a list - outstanding bug categories, each of which is tracked by a particular - tracker bug in bugzilla from which you can find several closely related - bug reports. - - doc/code-overview.txt provides a fairly good overview of the code, - including coverage of the function of the various files, the main - structures and their relationships, and places to start looking in the - code tailored to general categories of tasks. - - Ideas for tasks to work on - - There are a variety of things you could work on in the code. You may - have ideas of your own, but in case you don't, let me provide a list of - ideas you could choose from: - - If you're ambitious, there's a list of things Havoc made that he'd really - like to see tackled, which you can find at - http://log.ometer.com/2004-05.html. Be sure to double check with someone - to make sure the item is still relevant if you're interested in one of - these. Another place to look for ideas, of course, is bugzilla. One can - just do queries and look for things that look fixable. - - However, perhaps the best way of getting ideas of related tasks to work - on, is to look at the second half of the rationales.txt file, which tries - to group bugs by type. diff --git a/MAINTAINERS b/MAINTAINERS deleted file mode 100644 index 0031c7f..0000000 --- a/MAINTAINERS +++ /dev/null @@ -1,8 +0,0 @@ -Tomas Frydrych -Email: tf linux intel com -Userid: tomasf - -Owen Taylor -Email: otaylor redhat com -Userid: otaylor - diff --git a/METACITY_MAINTAINERS b/METACITY_MAINTAINERS deleted file mode 100644 index 205dbf2..0000000 --- a/METACITY_MAINTAINERS +++ /dev/null @@ -1,43 +0,0 @@ -Currently active maintainers --------------------------------- - -Elijah Newren -Email: newren gmail com -Userid: newren - - - Usually won't touch the theme bugs (isn't interested) or the - compositor (until open source nvidia drivers are up to snuff). - Tends to be most interested in libwnck/gtk interactions, focus - issues, constraints problems, and raising/stacking, but works on - just about anything other than themes and the compositor. - -Thomas Thurman -Email: thomas thurman org uk -Userid: tthurman - - - Responsible for all theme bugs and the compositor (thank goodness - Thomas got involved, eh?). I'm sure he'll replace this sentence - with his interests when he reads it. ;-) - - -Semi-active maintainers --------------------------------- - -Havoc Pennington -Email: hp redhat com -Userid: hp - - Original author. Doesn't patch metacity anymore, but is active in - answering questions, responding to bugs, providing very helpful - suggestions and insight, and even assisting with debugging. - - -Important historical figureheads --------------------------------- - -Rob Adams (readams readams net) - - Was the main maintainer of metacity for a while; particular areas - of focus included xinerama, placement, and an older version of the - constraints code. Still responds to bugs every once in a while. - -Søren Sandmann (sandmann redhat com) - - Wrote most of the current compositing manager code + libcm diff --git a/Makefile.am b/Makefile.am index 114419e..b55c1d1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,8 +3,6 @@ SUBDIRS=src po doc ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} -EXTRA_DIST = HACKING MAINTAINERS rationales.txt - DISTCLEANFILES = intltool-extract intltool-merge intltool-update po/stamp-it po/.intltool-merge-cache DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc @@ -1,23 +1,21 @@ 3.12.0 ====== +* Fix grab issue with SSD xwayland windows [Rui; #726123] +* Misc. bug fixes [Jasper, Ray, Rui, Florian; #727011] -Translations: - Ask H. Larsen [da], Мирослав Николић [sr, sr@latin], Andika Triwidada [id], - Daniel Korostil [uk], Petr Kovar [cs] +Contributors: + Rui Matos, Florian Müllner, Jasper St. Pierre, Ray Strode 3.11.92 ======= * Fix identification of CSD windows [Owen; #723029] -* Add minimal handling of touch events [Carlos; #723552] -* Misc bug fixes and cleanups [Owen, Adel, Jasper; #723580, #726352] +* Update keyboard state unconditionally [Rui; #722847] +* Misc bug fixes and cleanups [Owen, Rui, Giovanni, Matthias, Adel, Ryan, + Jasper, Marek, Florian; #723580, #726123, #726683] Contributors: - Adel Gadllah, Carlos Garnacho, Rui Matos, Jasper St. Pierre, Owen W. Taylor - -Translations: - Changwoo Ryu [ko], Rūdolfs Mazurs [lv], Wylmer Wang [zh_CN], - Chao-Hsiung Liao [zh_HK, zh_TW], Yuri Myasoedov [ru], Tiagosdot [pt], - Claude Paroz [fr], Duarte Loreto [pt], A S Alam [pa] + Giovanni Campagna, Marek Chalupa, Matthias Clasen, Adel Gadllah, Ryan Lortie, + Rui Matos, Florian Müllner, Jasper St. Pierre, Owen W. Taylor 3.11.91 ======= @@ -26,125 +24,104 @@ Translations: * Improve keybinding lookups [Rui; #725588] * Fix dynamic updates of titlebar style properties [Owen; #725751] * Fix positioning of manually positioned windows [Owen; #724049] -* Misc. bug fixes [Carlos, Giovanni, Florian, Jasper; #724969, #724402, #722266, - #725338] +* Misc bug fixes and cleanups [Jasper, Carlos, Adel, Giovanni, Florian; #720631, + #724969, #725216, #724402, #722266, #725338, #725525] Contributors: Giovanni Campagna, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner, - Jasper St. Pierre - -Translations: - Aurimas Černius [lt], Milo Casagrande [it], Balázs Úr [hu], - Matej Urbančič [sl], Enrico Nicoletto [pt_BR], Yosef Or Boczko [he], - Piotr Drąg [pl], Fran Diéguez [gl] + Jasper St. Pierre, Owen W. Taylor 3.11.90 ======= -* Use correct output property for backlight control [Robert; #723606] * Fix double-scaling on high DPI resolutions [Adel; #723931] * Make tile previews a compositor effect [Stefano, Florian; #665758] -* Misc. bug fixes and cleanups [Ryan, Giovanni, Jasper; #722530, #724257, - #724258, #724364, #720631, #707851, #707897] +* Misc. bug fixes and cleanups [Ryan, Giovanni, Jasper, Adel; #722530, #724257, + #724258, #720631, #724364, #724472] Contributors: - Robert Ancell, Giovanni Campagna, Stefano Facchini, Adel Gadllah, + Giovanni Campagna, Marek Chalupa, Stefano Facchini, Adel Gadllah, Ryan Lortie, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz -Translations: - Shankar Prasad [kn], Khaled Hosny [ar], Marek Černocký [cs], - Kjartan Maraas [nb], Daniel Korostil [uk] - 3.11.5 ====== * Fix CSD titlebars being placed off-screen [Jasper; #719772] +* Add support for subsurfaces [Jonas; #705502] * Expose MetaWindow:skip-taskbar property [Florian; #723307] * Fix legacy tray icons showing up blank [Adel; #721596] * Fix configuration of cloned monitors [Adel; #710610] -* Misc bug fixes and cleanups [Jasper, Adel, Jonas; #720631, #723468, #723563] +* Misc bug fixes and cleanups [Jasper, Adel, Marek, Jonas; #720631, #723468, + #720818, #723563, #723564] Contributors: Jonas Ådahl, Marek Ch, Adel Gadllah, Florian Müllner, Jasper St. Pierre -Translations: - Rafael Ferreira [pt_BR], Enrico Nicoletto [pt_BR], Fran Diéguez [gl], - Chao-Hsiung Liao [zh_HK, zh_TW] - 3.11.4 ====== * Don't leave focus on windows that are being unmanaged [Owen; #711618] * Reduce server grabs [Daniel Drake; #721345, #721709] * Improve heuristic to determine display output name [Cosimo Cecchi; #721674] * Atomically unmaximize both directions [Jasper; #722108] -* Misc bug fixes [Debarshi, Andika; #721517, #721674] +* Misc bug fixes [Debarshi, Andika, Florian; #721517, #721674, #722347] Contributors: - Cosimo Cecchi, Daniel Drake, Debarshi Ray, Jasper St. Pierre, + Cosimo Cecchi, Daniel Drake, Florian Müllner, Debarshi Ray, Jasper St. Pierre, Andika Triwidada, Owen W. Taylor -Translations: - Rafael Ferreira [pt_BR], Dimitris Spingos [el], Daniel Mustieles [es], - Milo Casagrande [it], Yosef Or Boczko [he] - 3.11.3 ====== -* xrandr: Use "hotplug_mode_update" property [Marc-André; #711216] -* Fix position of attached dialogs for CSD windows [Giovanni, Owen; #707194] -* Fix focus issues with external OSKs [Jasper; #715030] +* Fix focus issues with external OSKs[Jasper; #715030] * Add a MetaCullable interface [Jasper; #714706] +* Fix window keybindings [Rui; #719724] +* Fix settings keyboard/pointer focus for new clients [Rui; #719725] * Fix window group paint volume [Owen; #719669] * Fix frame extents problems [Owen; #714707] * Add shortcut to move windows between monitors [Florian; #671054] * Fix problems with focus tracking [Owen; #720558] -* Misc. bug fixes and cleanups [Rui, Jasper, Owen; #712833, #678989, #720106, - #720417, #720630] +* Misc. bug fixes and cleanups: [Rui, Colin, Lionel, Jasper, Owen; #712833, + #719557, #719695, #719833, #678989, #720417, #720630] Contributors: - Robert Bragg, Giovanni Campagna, Marc-André Lureau, Rui Matos, Alberto Milone, - Florian Müllner, Sindhu S, Jasper St. Pierre, Rico Tzschichholz, - Owen W. Taylor - -Translations: - 甘露(Gan Lu) [zh_CN], Khaled Hosny [ar] + Lionel Landwerlin, Rui Matos, Alberto Milone, Florian Müllner, + Jasper St. Pierre, Rico Tzschichholz, Owen W. Taylor, Colin Walters 3.11.2 ====== +* Support setting a NULL opaque region [Andreas; #711518] +* Sync keymap from X to wayland [Giovanni; #707446] +* Implement support for subsurfaces [Jonas; #705502] +* Don't focus the no-focus-window for globally active windows [Jasper; #710296] +* Support "hotplug_mode_update" property [Marc-André; #711216] * Fix resize operations using mouse-button-modifier [Lionel; #710251] -* Misc. fixes and cleanups [Jasper, Rico, Florian; #711731] +* Fix position of attached modals for CSD windows [Giovanni, Owen; #707194] +* Misc. bug fixes [Rui, Jasper, Neil, Florian; #712247, #711731] Contributors: - Lionel Landwerlin, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz + Giovanni Campagna, Andreas Heider, Lionel Landwerlin, Marc-André Lureau, + Rui Matos, Florian Müllner, Neil Roberts, Sindhu S, Jasper St. Pierre, + Rico Tzschichholz, Owen W. Taylor, Jonas Ådahl 3.11.1 ====== -* Don't require at least one output device to be connected [Giovanni; #709009] -* Name the guard window [Andrew; #710346] +* Fix tile previews getting stuck on right click during drags [Lionel; #704759] * Use new UPower API [Bastien] +* Set hot spot when cursor set from wl_buffer [Jonas; #709593] * Expose min-backlight-step [Asad; #710380] -* Don't focus the no-focus-window for globally active windows [Jasper; #710296] -* Misc. fixes and cleanups [Jasper, Rico, Olav, Magdalen; #709776] +* Misc. bug fixes and cleanups [Jasper, Olav, Magdalen; #709776] Contributors: - Magdalen Berns, Giovanni Campagna, Asad Mehmood, Bastien Nocera, - Jasper St. Pierre, Rico Tzschichholz, Olav Vitters, Andrew Walton - -Translations: - Reinout van Schouwen [nl] + Magdalen Berns, Lionel Landwerlin, Asad Mehmood, Bastien Nocera, + Jasper St. Pierre, Olav Vitters, Jonas Ådahl 3.10.1 ====== * Don't apply fullscreen workarounds to CSD windows [Giovanni; #708718] * Fix hangs during DND operations [Adel; #709340] -* Use nearest-pixel interpolation when possible [Hans; #708389] -* Fix tile previews getting stuck on right click during drags [Lionel; #704759] -* Misc bug fixes [Giovanni, Jasper; #708420] +* Misc bug fixes [Dan, Giovanni, Jasper; #708813, #708420] Contributors: - Giovanni Campagna, Adel Gadllah, Lionel Landwerlin, Hans Petter Jansson, + Giovanni Campagna, Adel Gadllah, Dan Horák, Hans Petter Jansson, Jasper St. Pierre -Translations: - Khaled Hosny [ar], Reinout van Schouwen [nl], Carles Ferrando [ca@valencia] - 3.10.0.1 ======== * Fix bug when a window changed size twice in a single frame - this @@ -155,24 +132,32 @@ Contributors: 3.10.0 ====== - -Translations: - Ask H. Larsen [da], Gabor Kelemen [hu], Duarte Loreto [pt], - Yosef Or Boczko [he] +* Update dependencies [Giovanni; #708210] 3.9.92 ====== -* Don't create a dummy texture for the texture pipeline template [Neil; #707458] -* Remove holes generated by disabling the laptop lid [Giovanni; #707473] -* https://bugzilla.gnome.org/show_bug.cgi?id=707474 [Giovanni; #707474] +* Constrain the pointer position onto visible monitors [Giovanni; #706655] +* Fix keyboard state handling in face of event compression [Giovanni; #706963] +* Extend the MetaCursorTracker API with query pointer and cursor visibility [Giovanni; #707474] +* Be stricter in checking and exposing the wayland protocol version [#707851] * Don't require plugins to pass event to Clutter [Giovanni; #707482] +* Move the --wayland option from the binary to the library [Giovanni; #707897] +* Implement running from gnome-session (environment variable setting, process group + handling, Clutter backend variables) [Giovanni; #706421] * Add support for more cursor types [Giovanni; #707919] +* Drop man pages for removed utilities [Kalev; #706579] +* Implement monitor configuration on KMS [Giovanni; #706308] +* Implement HW cursors [Giovanni; #707573] +* Implement minimal support for resizing and maximizing wayland clients [Giovanni; #707401] +* Implement transient hints for wayland clients [Giovanni; #707401] +* Implement popup menu surfaces and grabs [Giovanni; #707863] * Immediately fire idle watches that are already expired [Giovanni; #707302] -* Misc bug fixes [Giovanni, Colin, Pavel; #707649, #707563, #708070] +* Remove holes generated by disabling the laptop lid [Giovanni; #707473] +* Misc bug fixes [Giovanni, Pavel, Adel; #707649, #706124, #707584, #707851, #707929, + #708070] Contributors: - Giovanni Campagna, Adel Gadllah, Colin Guthrie, Neil Roberts, - Jasper St. Pierre, Ray Strode, Pavel Vasin + Adel Gadllah, Giovanni Campagna, Kalev Lember, Pavel Vasin Translations: Мирослав Николић po/sr, sr@latin.po, Мирослав Николић [sr, sr@latin], @@ -185,19 +170,30 @@ Translations: 3.9.91 ====== * Drop man pages for removed utilities [Kalev; #706579] -* Add support for idle tracking [Giovanni; #706005] +* Add support for idle tracking [Giovanni, Cosimo; #706005, #707250] * Skip CRTC reconfigurations that have no effect [Giovanni; #706672] * Ignore skip-taskbar hints on parentless dialogs [Giovanni; #673399] * Don't save pixbuf data in user data [Tim; #706777] * Don't queue redraws for obscured regions [Adel; #703332] -* Turn blending off when drawing entirely opaque regions [Jasper; #706930] +* Suppor the opaque region hints for wayland clients [Jasper; #707019] +* Turn blending off when drawing entirely opaque regions [Jasper; #707019] * Check event timestamps before reconfiguring [Giovanni; #706735] +* Merge the DBus API for display configuration in the wayland branch [Giovanni] +* Install an X IO error handler for XWayland [Giovanni; #706962] +* Use the clutter xkbcommon integration for the wayland keyboard [Giovanni; #705862] +* Add a setuid helper for running on KMS+evdev [Giovanni, Colin; #705861] +* Add keybindings for switching VT [Giovanni; #705861] +* Implement plugin modality when running as a wayland compositor [Giovanni; #705917] +* Add support for the application menu for wayland clients [Giovanni; #707128] +* Several Coverity spotted fixes [Jasper] +* Don't create a dummy texture for the texture template [Neil; #707458] +* Use a more conservative paint volume for obscured windows [Adel] * Misc bug fixes [Giovanni, Colin, Seán, Jasper, Cosimo; #706582, #706598, - #706787, #706729, #706825, #707081, #707090, #707250, #707267] + #706787, #706729, #706825, #707081, #707090, #707267, #706982, #706289] Contributors: Giovanni Campagna, Cosimo Cecchi, Adel Gadllah, Colin Guthrie, Kalev Lember, - Tim Lunn, Jasper St. Pierre, Rico Tzschichholz, Seán de Búrca + Tim Lunn, Jasper St. Pierre, Neil Roberts, Rico Tzschichholz, Seán de Búrca Translations: Piotr Drąg [pl], Alexandre Franke [fr], Kjartan Maraas [nb], @@ -206,6 +202,8 @@ Translations: 3.9.90 ====== +* First release from the wayland branch, includes basic support for running + as a wayland compositor [Robert, Neil, Giovanni] * Add support for _GTK_FRAME_EXTENTS [Jasper; #705766] * Fix quick consecutive <super> presses breaking keyboard input [Alban; #666101] * Work towards running as wayland compositor [Giovanni] @@ -220,8 +218,8 @@ Translations: Contributors: Robert Bragg, Giovanni Campagna, Alban Crequy, Adel Gadllah, - Alexander Larsson, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz, - Colin Walters + Alexander Larsson, Florian Müllner, Jasper St. Pierre, Neil Roberts, + Rico Tzschichholz, Colin Walters Translations: Jiro Matsuzawa [ja], Kjartan Maraas [nb], Matej Urbančič [sl], @@ -1,416 +0,0 @@ -The original codebase named "Metacity" is not a meta-City as in an -urban center, but rather Meta-ness as in the state of being -meta. i.e. metacity : meta as opacity : opaque. Also it may have -something to do with the Meta key on UNIX keyboards. - -Since then, it has been renamed mutter after a rebase on top of -clutter as a compositing manager. - -COMPILING MUTTER -=== - -You need GTK+ 2.2. For startup notification to work you need -libstartup-notification at -http://www.freedesktop.org/software/startup-notification/ or on the -GNOME ftp site. -You need Clutter 1.0. You need gobject-introspection 0.6.3. - -REPORTING BUGS AND SUBMITTING PATCHES -=== - -Report new bugs on http://bugzilla.gnome.org. Please check for -duplicates, *especially* if you are reporting a feature request. - -Please do *not* add "me too!" or "yes I really want this!" comments to -feature requests in bugzilla. Please read -http://pobox.com/~hp/features.html prior to adding any kind of flame -about missing features or misfeatures. - -Feel free to send patches too; Metacity is relatively small and -simple, so if you find a bug or want to add a feature it should be -pretty easy. Send me mail, or put the patch in bugzilla. - -See the HACKING file for some notes on hacking Mutter. - -MUTTER FEATURES -=== - - - Uses GTK+ 2.0 for drawing window frames. This means colors, fonts, - etc. come from GTK+ theme. - - - Does not expose the concept of "window manager" to the user. Some - of the features in the GNOME control panel and other parts of the - desktop happen to be implemented in metacity, such as changing your - window border theme, or changing your window navigation shortcuts, - but the user doesn't need to know this. - - - Includes only the window manager; does not try to be a desktop - environment. The pager, configuration, etc. are all separate and - modular. The "libwnck" library (which I also wrote) is available - for writing metacity extensions, pagers, and so on. (But libwnck - isn't metacity specific, or GNOME-dependent; it requires only GTK, - and should work with KWin, fvwm2, and other EWMH-compliant WMs.) - - - Has a simple theme system and a couple of extra themes come with it. - Change themes via gsettings: - gsettings set org.gnome.desktop.wm.preferences theme Crux - gsettings set org.gnome.desktop.wm.preferences theme Gorilla - gsettings set org.gnome.desktop.wm.preferences theme Atlanta - gsettings set org.gnome.desktop.wm.preferences theme Bright - - See theme-format.txt for docs on the theme format. Use - metacity-theme-viewer to preview themes. - - - Change number of workspaces via gsettings: - gsettings set org.gnome.desktop.wm.preferences num-workspaces 5 - - Can also change workspaces from GNOME 2 pager. - - - Change focus mode: - gsettings set org.gnome.desktop.wm.preferences focus-mode mouse - gsettings set org.gnome.desktop.wm.preferences focus-mode sloppy - gsettings set org.gnome.desktop.wm.preferences focus-mode click - - - Global keybinding defaults include: - - Alt-Tab forward cycle window focus - Alt-Shift-Tab backward cycle focus - Alt-Ctrl-Tab forward cycle focus among panels - Alt-Ctrl-Shift-Tab backward cycle focus among panels - Alt-Escape cycle window focus without a popup thingy - Ctrl-Alt-Left Arrow previous workspace - Ctrl-Alt-Right Arrow next workspace - Ctrl-Alt-D minimize/unminimize all, to show desktop - - Change keybindings for example: - - gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-1 '[<Alt>F1]' - - Also try the GNOME keyboard shortcuts control panel. - - - Window keybindings: - - Alt-space window menu - - Mnemonics work in the menu. That is, Alt-space then underlined - letter in the menu item works. - - Choose Move from menu, and arrow keys to move the window. - - While moving, hold down Control to move slower, and - Shift to snap to edges. - - Choose Resize from menu, and nothing happens yet, but - eventually I might implement something. - - Keybindings for things like maximize window, vertical maximize, - etc. can be bound, but may not all exist by default. See - metacity.schemas. - - - Window mouse bindings: - - Clicking anywhere on frame with button 1 will raise/focus window - - If you click a window control, such as the close button, then the - control will activate on button release if you are still over it - on release (as with most GUI toolkits) - - If you click and drag borders with button 1 it resizes the window - - If you click and drag the titlebar with button 1 it moves the - window. - - If you click anywhere on the frame with button 2 it lowers the - window. - - If you click anywhere on the frame with button 3 it shows the - window menu. - - If you hold down Super (windows key) and click inside a window, it - will move the window (buttons 1 and 2) or show menu (button 3). - Or you can configure a different modifier for this. - - If you pick up a window with button 1 and then switch workspaces - the window will come with you to the new workspace, this is - a feature copied from Enlightenment. - - If you hold down Shift while moving a window, the window snaps - to edges of other windows and the screen. - - - Session management: - - Mutter connects to the session manager and will set itself up to - be respawned. It theoretically restores sizes/positions/workspace - for session-aware applications. - - - Mutter implements much of the EWMH window manager specification - from freedesktop.org, as well as the older ICCCM. Please refer to - the COMPLIANCE file for information on mutter compliance with - these standards. - - - Uses Pango to render text, so has cool i18n capabilities. - Supports UTF-8 window titles and such. - - - There are simple animations for actions such as minimization, - to help users see what is happening. Should probably - have a few more of these and make them nicer. - - - if you have the proper X setup, set the GDK_USE_XFT=1 - environment variable to get antialiased window titles. - - - considers the panel when placing windows and maximizing - them. - - - handles the window manager selection from the ICCCM. Will exit if - another WM claims it, and can claim it from another WM if you pass - the --replace argument. So if you're running another - ICCCM-compliant WM, you can run "mutter --replace" to replace it - with Metacity. - - - does basic colormap handling - - - and much more! well, maybe not a lot more. - -HOW TO ADD EXTERNAL FEATURES -=== - -You can write a mutter "plugin" such as a pager, window list, icon -box, task menu, or even things like "window matching" using the -Extended Window Manager Hints. See http://www.freedesktop.org for the -EWMH specification. An easy-to-use library called "libwnck" is -available that uses the EWMH and is specifically designed for writing -WM accessories. - -You might be interested in existing accessories such as "Devil's Pie" -by Ross Burton, which add features to Mutter (or other -EWMH-compliant WMs). - -MUTTER BUGS, NON-FEATURES, AND CAVEATS -=== - -See bugzilla: http://bugzilla.gnome.org/query.cgi - -FAQ -=== - -Q: Will you add my feature? - -A: If it makes sense to turn on unconditionally, or is genuinely a - harmless preference that I would not be embarrassed to put in a - simple, uncluttered, user-friendly configuration dialog. - - If the only rationale for your feature is that other window - managers have it, or that you are personally used to it, or - something like that, then I will not be impressed. Metacity is - firmly in the "choose good defaults" camp rather than the "offer 6 - equally broken ways to do it, and let the user pick one" camp. - - This is part of a "no crackrock" policy, despite some exceptions - I'm mildly embarrassed about. For example, multiple workspaces - probably constitute crackrock, they confuse most users and really - are not that useful if you have a decent tasklist and so on. But I - am too used to them to turn them off. Or alternatively - iconification/tasklist is crack, and workspaces/pager are good. But - having both is certainly a bit wrong. Sloppy focus is probably - crackrock too. - - But don't think unlimited crack is OK just because I slipped up a - little. No slippery slope here. - - Don't let this discourage patches and fixes - I love those. ;-) - Just be prepared to hear the above objections if your patch adds - some crack-ridden configuration option. - - http://pobox.com/~hp/free-software-ui.html - http://pobox.com/~hp/features.html - -Q: Will Mutter be part of GNOME? - -A: It is not officially part of GNOME as of GNOME 2.27. We are - hoping to have mutter officially included as of GNOME 2.28. - -Q: Why does Mutter remember the workspace/position of some apps - but not others across logout/login? - -A: Mutter only stores sizes/positions for apps that are session - managed. As far as I can determine, there is no way to attempt to - remember workspace/position for non-session-aware apps without - causing a lot of weird effects. - - The reason is that you don't know which non-SM-aware apps were - launched by the session. When you initially log in, Metacity sees a - bunch of new windows appear. But it can't distinguish between - windows that were stored in your session, or windows you just - launched after logging in. If Metacity tried to guess that a window - was from the session, it could e.g. end up maximizing a dialog, or - put a window you just launched on another desktop or in a weird - place. And in fact I see a lot of bugs like this in window managers - that try to handle non-session-aware apps. - - However, for session-aware apps, Mutter can tell that the - application instance is from the session and thus restore it - reliably, assuming the app properly restores the windows it had - open on session save. - - So the correct way to fix the situation is to make apps - session-aware. libSM has come with X for years, it's very - standardized, it's shared by GNOME and KDE - even twm is - session-aware. So anyone who won't take a patch to add SM is more - archaic than twm - and you should flame them. ;-) - - Docs on session management: - http://www.fifi.org/doc/xspecs/xsmp.txt.gz - http://www.fifi.org/doc/xspecs/SMlib.txt.gz - - See also the ICCCM section on SM. For GNOME apps, use the - GnomeClient object. For a simple example of using libSM directly, - twm/session.c in the twm source code is pretty easy to understand. - -Q: How about adding viewports in addition to workspaces? - -A: I could conceivably be convinced to use viewports _instead_ of - workspaces, though currently I'm not thinking that. But I don't - think it makes any sense to have both; it's just confusing. They - are functionally equivalent. - - You may think this means that you won't have certain keybindings, - or something like that. This is a misconception. The only - _fundamental_ difference between viewports and workspaces is that - with viewports, windows can "overlap" and appear partially on - one and partially on another. All other differences that - traditionally exist in other window managers are accidental - - the features commonly associated with viewports can be implemented - for workspaces, and vice versa. - - So I don't want to have two kinds of - workspace/desktop/viewport/whatever, but I'm willing to add - features traditionally associated with either kind if those - features make sense. - -Q: Why is the panel always on top? - -A: Because it's a better user interface, and until we made this not - configurable a bunch of apps were not getting fixed (the app - authors were just saying "put your panel on the bottom" instead of - properly supporting fullscreen mode, and such). - - rationales.txt has the bugzilla URL for some flamefesting on this, - if you want to go back and relive the glory. - Read these and the bugzilla stuff before asking/commenting: - http://pobox.com/~hp/free-software-ui.html - http://pobox.com/~hp/features.html - -Q: Why is there no edge flipping? - -A: This one is also in rationales.txt. Because "ouija board" UI, where - you just move the mouse around and the computer guesses what you - mean, has a lot of issues. This includes mouse focus, shade-hover - mode, edge flipping, autoraise, etc. Metacity has mouse focus and - autoraise as a compromise, but these features are all confusing for - many users, and cause problems with accessibility, fitt's law, and - so on. - - Read these and the bugzilla stuff before asking/commenting: - http://pobox.com/~hp/free-software-ui.html - http://pobox.com/~hp/features.html - -Q: Why does wireframe move/resize suck? - -A: You can turn it on with the reduced_resources setting. - - But: it has low usability, and is a pain - to implement, and there's no reason opaque move/resize should be a - problem on any setup that can run a modern desktop worth a darn to - begin with. - - Read these and the bugzilla stuff before asking/commenting: - http://pobox.com/~hp/free-software-ui.html - http://pobox.com/~hp/features.html - - The reason we had to add wireframe anyway was broken - proprietary apps that can't handle lots of resize events. - -Q: Why no XYZ? - -A: You are probably getting the idea by now - check rationales.txt, - query/search bugzilla, and read http://pobox.com/~hp/features.html - and http://pobox.com/~hp/free-software-ui.html - - Then sit down and answer the question for yourself. Is the feature - good? What's the rationale for it? Answer "why" not just "why not." - Justify in terms of users as a whole, not just users like - yourself. How else can you solve the same problem? etc. If that - leads you to a strong opinion, then please, post the rationale for - discussion to an appropriate bugzilla bug, or to - usability@gnome.org. - - Please don't just "me too!" on bugzilla bugs, please don't think - flames will get you anywhere, and please don't repeat rationale - that's already been offered. - -Q: Your dumb web pages you made me read talk about solving problems in - fundamental ways instead of adding preferences or workarounds. - What are some examples where metacity has done this? - -A: There are quite a few, though many opportunities remain. Sometimes - the real fix involves application changes. The metacity approach is - that it's OK to require apps to change, though there are also - plenty of workarounds in metacity for battles considered too hard - to fight. - - Here are some examples: - - - fullscreen mode was introduced to allow position constraints, - panel-on-top, and other such things to apply to normal windows - while still allowing video players etc. to "just work" - - - "whether to include minimized windows in Alt+Tab" was solved - by putting minimized windows at the *end* of the tab order. - - - Whether to pop up a feedback display during Alt+Tab was solved by - having both Alt+Tab and Alt+Esc - - - Whether to have a "kill" feature was solved by automatically - detecting and offering to kill stuck apps. Better, metacity - actually does "kill -9" on the process, it doesn't just - disconnect the process from the X server. You'll appreciate this - if you ever did a "kill" on Netscape 4, and watched it keep - eating 100% CPU even though the X server had booted it. - - - The workspaces vs. viewports mess was avoided by adding - directional navigation and such to workspaces, see discussion - earlier in this file. - - - Instead of configurable placement algorithms, there's just one - that works fairly well most of the time. - - - To avoid excess CPU use during opaque move/resize, we rate limit - the updates to the application window's size. - - - Instead of configurable "show size of window while resizing," - it's only shown for windows where it matters, such as terminals. - (Only use-case given for all windows is for web designers - choosing their web browser size, but there are web sites and - desktop backgrounds that do this for you.) - - - Using startup notification, applications open on the workspace - where you launched them, not the active workspace when their - window is opened. - - - and much more. - -Q: I think mutter sucks. - -A: Feel free to use any WM you like. The reason metacity follows the - ICCCM and EWMH specifications is that it makes metacity a modular, - interchangeable part in the desktop. libwnck-based apps such as the - GNOME window list will work just fine with any EWMH-compliant WM. - -Q: Did you spend a lot of time on this? - -A: Originally the answer was no. Sadly the answer is now yes. - -Q: How can you claim that you are anti-crack, while still - writing a window manager? - -A: I have no comment on that. diff --git a/configure.ac b/configure.ac index f27be5c..ea9e674 100644 --- a/configure.ac +++ b/configure.ac @@ -17,10 +17,14 @@ AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR(src/core/display.c) AC_CONFIG_HEADERS(config.h) -AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar]) +AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz tar-ustar subdir-objects]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) AM_MAINTAINER_MODE([enable]) +# Change pkglibdir and pkgdatadir to mutter-wayland instead of mutter +PACKAGE="mutter-wayland" +AC_SUBST([PACKAGE], [$PACKAGE]) + MUTTER_MAJOR_VERSION=mutter_major_version MUTTER_MINOR_VERSION=mutter_minor_version MUTTER_MICRO_VERSION=mutter_micro_version @@ -36,7 +40,7 @@ AC_SUBST(MUTTER_PLUGIN_DIR) # Honor aclocal flags AC_SUBST(ACLOCAL_AMFLAGS, "\${ACLOCAL_FLAGS}") -GETTEXT_PACKAGE=mutter +GETTEXT_PACKAGE=mutter-wayland AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[Name of default gettext domain]) @@ -75,7 +79,7 @@ MUTTER_PC_MODULES=" cairo >= 1.10.0 gsettings-desktop-schemas >= 3.7.3 xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0 - $CLUTTER_PACKAGE >= 1.15.90 + $CLUTTER_PACKAGE >= 1.17.5 cogl-1.0 >= 1.17.1 upower-glib >= 0.99.0 gnome-desktop-3.0 @@ -117,11 +121,27 @@ AC_ARG_ENABLE(shape, [disable mutter's use of the shaped window extension]),, enable_shape=auto) +## Wayland support requires the xserver.xml protocol extension found in the weston +## repository but since there aren't currently established conventions for +## installing and discovering these we simply require a location to be given +## explicitly... +AC_ARG_WITH([wayland-protocols], + [AS_HELP_STRING([--with-wayland-protocols], [Location for wayland extension protocol specs])], + [ + ], + []) + +AC_ARG_WITH([xwayland-path], + [AS_HELP_STRING([--with-xwayland-path], [Absolute path for an X Wayland server])], + [XWAYLAND_PATH="$withval"], + [XWAYLAND_PATH="$bindir/Xwayland"]) + AM_GLIB_GNU_GETTEXT ## here we get the flags we'll actually use # GRegex requires Glib-2.14.0 PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0) +PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login) # Unconditionally use this dir to avoid a circular dep with gnomecc GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings" @@ -186,20 +206,15 @@ if test x$found_introspection != xno; then AC_SUBST(META_GIR) fi -AC_MSG_CHECKING([Xcursor]) -if $PKG_CONFIG xcursor; then - have_xcursor=yes - else - have_xcursor=no - fi - AC_MSG_RESULT($have_xcursor) +MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor" -if test x$have_xcursor = xyes; then - echo "Building with Xcursor" - MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor" - AC_DEFINE(HAVE_XCURSOR, , [Building with Xcursor support]) -fi +AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no]) +AS_IF([test "x$WAYLAND_SCANNER" = "xno"], + AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols])) +AC_SUBST([WAYLAND_SCANNER]) +AC_SUBST(XWAYLAND_PATH) +MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm" PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES) PKG_CHECK_EXISTS([xi >= 1.6.99.1], @@ -437,8 +452,7 @@ doc/man/Makefile doc/reference/Makefile doc/reference/meta-docs.sgml src/Makefile -src/libmutter.pc -src/mutter-plugins.pc +src/libmutter-wayland.pc src/compositor/plugins/Makefile po/Makefile.in ]) @@ -455,7 +469,7 @@ fi dnl ========================================================================== echo " -mutter-$VERSION +mutter-wayland-$VERSION prefix: ${prefix} source code location: ${srcdir} @@ -467,7 +481,6 @@ mutter-$VERSION Session management: ${found_sm} Shape extension: ${found_shape} Xsync: ${found_xsync} - Xcursor: ${have_xcursor} " diff --git a/doc/Makefile.am b/doc/Makefile.am index d16ae33..12dc522 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,4 +1,4 @@ SUBDIRS = man reference EXTRA_DIST=theme-format.txt dialogs.txt code-overview.txt \ - how-to-get-focus-right.txt + how-to-get-focus-right.txt rationales.txt diff --git a/rationales.txt b/doc/rationales.txt index 600d2d5..600d2d5 100644 --- a/rationales.txt +++ b/doc/rationales.txt diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am index f411e26..e0e702e 100644 --- a/doc/reference/Makefile.am +++ b/doc/reference/Makefile.am @@ -140,7 +140,7 @@ expand_content_files= \ # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) GTKDOC_CFLAGS=$(MUTTER_CFLAGS) -GTKDOC_LIBS=$(MUTTER_LIBS) $(top_builddir)/src/libmutter.la +GTKDOC_LIBS=$(MUTTER_LIBS) $(top_builddir)/src/libmutter-wayland.la # This includes the standard gtk-doc make rules, copied by gtkdocize. include $(top_srcdir)/gtk-doc.make diff --git a/po/POTFILES.in b/po/POTFILES.in index fb89335..f6696d9 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -16,14 +16,14 @@ src/core/monitor.c src/core/mutter.c src/core/prefs.c src/core/screen.c -src/core/session.c +src/x11/session.c src/core/util.c src/core/window.c -src/core/window-props.c -src/core/xprops.c -src/mutter.desktop.in -src/mutter-wm.desktop.in +src/x11/window-props.c +src/x11/xprops.c +src/mutter-wayland.desktop.in src/org.gnome.mutter.gschema.xml.in +src/org.gnome.mutter.wayland.gschema.xml.in src/ui/frames.c src/ui/menu.c src/ui/metaaccellabel.c diff --git a/src/Makefile.am b/src/Makefile.am index dc1cac7..61cbb7a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,16 +1,19 @@ # Flag build for parallelism; see https://savannah.gnu.org/patch/?6905 .AUTOPARALLEL: -lib_LTLIBRARIES = libmutter.la +lib_LTLIBRARIES = libmutter-wayland.la SUBDIRS=compositor/plugins INCLUDES= \ + -DCLUTTER_ENABLE_COMPOSITOR_API \ -DCLUTTER_ENABLE_EXPERIMENTAL_API \ -DCOGL_ENABLE_EXPERIMENTAL_API \ -DCOGL_ENABLE_EXPERIMENTAL_2_0_API \ $(MUTTER_CFLAGS) \ + -I$(top_builddir) \ -I$(srcdir) \ + -I$(srcdir)/backends \ -I$(srcdir)/core \ -I$(srcdir)/ui \ -I$(srcdir)/compositor \ @@ -27,17 +30,56 @@ INCLUDES= \ -DMUTTER_PLUGIN_API_VERSION=$(MUTTER_PLUGIN_API_VERSION) \ -DMUTTER_PKGLIBDIR=\"$(pkglibdir)\" \ -DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\" \ - -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" + -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \ + -DXWAYLAND_PATH='"@XWAYLAND_PATH@"' mutter_built_sources = \ - $(dbus_idle_built_sources) \ - $(dbus_xrandr_built_sources) \ - mutter-enum-types.h \ - mutter-enum-types.c - -libmutter_la_SOURCES = \ - core/async-getprop.c \ - core/async-getprop.h \ + $(dbus_idle_built_sources) \ + $(dbus_display_config_built_sources) \ + mutter-enum-types.h \ + mutter-enum-types.c \ + gtk-shell-protocol.c \ + gtk-shell-server-protocol.h \ + xdg-shell-protocol.c \ + xdg-shell-server-protocol.h + +wayland_protocols = \ + wayland/protocol/gtk-shell.xml \ + wayland/protocol/xdg-shell.xml + +libmutter_wayland_la_SOURCES = \ + backends/meta-backend.c \ + backends/meta-backend.h \ + backends/meta-cursor.c \ + backends/meta-cursor.h \ + backends/meta-cursor-private.h \ + backends/meta-cursor-tracker.c \ + backends/meta-cursor-tracker-private.h \ + backends/meta-idle-monitor.c \ + backends/meta-idle-monitor-private.h \ + backends/meta-idle-monitor-dbus.c \ + backends/meta-idle-monitor-dbus.h \ + backends/meta-monitor-config.c \ + backends/meta-monitor-config.h \ + backends/meta-monitor-manager.c \ + backends/meta-monitor-manager.h \ + backends/meta-monitor-manager-dummy.c \ + backends/meta-monitor-manager-dummy.h \ + backends/edid-parse.c \ + backends/edid.h \ + backends/native/meta-idle-monitor-native.c \ + backends/native/meta-idle-monitor-native.h \ + backends/native/meta-monitor-manager-kms.c \ + backends/native/meta-monitor-manager-kms.h \ + backends/native/meta-weston-launch.c \ + backends/native/meta-weston-launch.h \ + backends/x11/meta-idle-monitor-xsync.c \ + backends/x11/meta-idle-monitor-xsync.h \ + backends/x11/meta-monitor-manager-xrandr.c \ + backends/x11/meta-monitor-manager-xrandr.h \ + backends/x11/meta-xrandr-shared.h \ + core/meta-accel-parse.c \ + core/meta-accel-parse.h \ core/barrier.c \ meta/barrier.h \ core/bell.c \ @@ -65,7 +107,13 @@ libmutter_la_SOURCES = \ compositor/meta-shadow-factory.c \ compositor/meta-shadow-factory-private.h \ compositor/meta-shaped-texture.c \ - compositor/meta-shaped-texture-private.h \ + compositor/meta-shaped-texture-private.h \ + compositor/meta-surface-actor.c \ + compositor/meta-surface-actor.h \ + compositor/meta-surface-actor-x11.c \ + compositor/meta-surface-actor-x11.h \ + compositor/meta-surface-actor-wayland.c \ + compositor/meta-surface-actor-wayland.h \ compositor/meta-texture-rectangle.c \ compositor/meta-texture-rectangle.h \ compositor/meta-texture-tower.c \ @@ -86,7 +134,6 @@ libmutter_la_SOURCES = \ meta/meta-shadow-factory.h \ meta/meta-window-actor.h \ meta/compositor-mutter.h \ - core/above-tab-keycode.c \ core/constraints.c \ core/constraints.h \ core/core.c \ @@ -96,34 +143,17 @@ libmutter_la_SOURCES = \ meta/display.h \ core/edge-resistance.c \ core/edge-resistance.h \ - core/edid-parse.c \ - core/edid.h \ + core/events.c \ + core/events.h \ core/errors.c \ meta/errors.h \ core/frame.c \ core/frame.h \ ui/gradient.c \ meta/gradient.h \ - core/group-private.h \ - core/group-props.c \ - core/group-props.h \ - core/group.c \ - meta/group.h \ - core/iconcache.c \ - core/iconcache.h \ core/keybindings.c \ core/keybindings-private.h \ core/main.c \ - core/meta-cursor-tracker.c \ - core/meta-cursor-tracker-private.h \ - core/meta-idle-monitor.c \ - core/meta-idle-monitor-private.h \ - core/meta-xrandr-shared.h \ - core/monitor.c \ - core/monitor-config.c \ - core/monitor-private.h \ - core/monitor-xrandr.c \ - core/mutter-Xatomtype.h \ core/place.c \ core/place.h \ core/prefs.c \ @@ -132,8 +162,6 @@ libmutter_la_SOURCES = \ core/screen-private.h \ meta/screen.h \ meta/types.h \ - core/session.c \ - core/session.h \ core/stack.c \ core/stack.h \ core/stack-tracker.c \ @@ -141,15 +169,11 @@ libmutter_la_SOURCES = \ core/util.c \ meta/util.h \ core/util-private.h \ - core/window-props.c \ - core/window-props.h \ core/window.c \ core/window-private.h \ meta/window.h \ core/workspace.c \ core/workspace-private.h \ - core/xprops.c \ - core/xprops.h \ meta/common.h \ core/core.h \ ui/ui.h \ @@ -165,13 +189,54 @@ libmutter_la_SOURCES = \ ui/theme.c \ meta/theme.h \ ui/theme-private.h \ - ui/ui.c - -nodist_libmutter_la_SOURCES = \ + ui/ui.c \ + x11/iconcache.c \ + x11/iconcache.h \ + x11/async-getprop.c \ + x11/async-getprop.h \ + x11/group-private.h \ + x11/group-props.c \ + x11/group-props.h \ + x11/group.c \ + meta/group.h \ + x11/session.c \ + x11/session.h \ + x11/window-props.c \ + x11/window-props.h \ + x11/window-x11.c \ + x11/window-x11.h \ + x11/window-x11-private.h \ + x11/xprops.c \ + x11/xprops.h \ + x11/mutter-Xatomtype.h \ + wayland/meta-wayland.c \ + wayland/meta-wayland.h \ + wayland/meta-wayland-private.h \ + wayland/meta-xwayland.c \ + wayland/meta-xwayland.h \ + wayland/meta-xwayland-private.h \ + wayland/meta-wayland-data-device.c \ + wayland/meta-wayland-data-device.h \ + wayland/meta-wayland-keyboard.c \ + wayland/meta-wayland-keyboard.h \ + wayland/meta-wayland-pointer.c \ + wayland/meta-wayland-pointer.h \ + wayland/meta-wayland-seat.c \ + wayland/meta-wayland-seat.h \ + wayland/meta-wayland-stage.h \ + wayland/meta-wayland-stage.c \ + wayland/meta-wayland-surface.c \ + wayland/meta-wayland-surface.h \ + wayland/meta-wayland-types.h \ + wayland/meta-wayland-versions.h \ + wayland/window-wayland.c \ + wayland/window-wayland.h + +nodist_libmutter_wayland_la_SOURCES = \ $(mutter_built_sources) -libmutter_la_LDFLAGS = -no-undefined -libmutter_la_LIBADD = $(MUTTER_LIBS) +libmutter_wayland_la_LDFLAGS = -no-undefined +libmutter_wayland_la_LIBADD = $(MUTTER_LIBS) # Headers installed for plugins; introspected information will # be extracted into Mutter-<version>.gir @@ -209,16 +274,29 @@ libmutterinclude_base_headers = \ libmutterinclude_extra_headers = \ meta/atomnames.h -libmutterincludedir = $(includedir)/mutter/meta +libmutterincludedir = $(includedir)/mutter-wayland/meta libmutterinclude_HEADERS = \ $(libmutterinclude_base_headers) \ $(libmutterinclude_extra_headers) -bin_PROGRAMS=mutter +bin_PROGRAMS=mutter-wayland + +mutter_wayland_SOURCES = core/mutter.c +mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la + +bin_PROGRAMS+=mutter-launch + +mutter_launch_SOURCES = \ + backends/native/weston-launch.c \ + backends/native/weston-launch.h + +mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS) -DLIBDIR=\"$(libdir)\" +mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam -mutter_SOURCES = core/mutter.c -mutter_LDADD = $(MUTTER_LIBS) libmutter.la +install-exec-hook: + -chown root $(DESTDIR)$(bindir)/mutter-launch + -chmod u+s $(DESTDIR)$(bindir)/mutter-launch if HAVE_INTROSPECTION include $(INTROSPECTION_MAKEFILE) @@ -240,41 +318,36 @@ typelib_DATA = Meta-$(api_version).typelib INTROSPECTION_GIRS = Meta-$(api_version).gir -Meta-$(api_version).gir: libmutter.la +Meta-$(api_version).gir: libmutter-wayland.la @META_GIR@_INCLUDES = GObject-2.0 GDesktopEnums-3.0 Gdk-3.0 Gtk-3.0 Clutter-1.0 xlib-2.0 xfixes-4.0 Cogl-1.0 -@META_GIR@_EXPORT_PACKAGES = libmutter +@META_GIR@_EXPORT_PACKAGES = libmutter-wayland @META_GIR@_CFLAGS = $(INCLUDES) -@META_GIR@_LIBS = libmutter.la +@META_GIR@_LIBS = libmutter-wayland.la @META_GIR@_FILES = \ mutter-enum-types.h \ $(libmutterinclude_base_headers) \ - $(filter %.c,$(libmutter_la_SOURCES) $(nodist_libmutter_la_SOURCES)) + $(filter %.c,$(libmutter_wayland_la_SOURCES) $(nodist_libmutter_wayland_la_SOURCES)) @META_GIR@_SCANNERFLAGS = --warn-all --warn-error endif testboxes_SOURCES = core/testboxes.c testgradient_SOURCES = ui/testgradient.c -testasyncgetprop_SOURCES = core/testasyncgetprop.c +testasyncgetprop_SOURCES = x11/testasyncgetprop.c noinst_PROGRAMS=testboxes testgradient testasyncgetprop -testboxes_LDADD = $(MUTTER_LIBS) libmutter.la -testgradient_LDADD = $(MUTTER_LIBS) libmutter.la -testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la +testboxes_LDADD = $(MUTTER_LIBS) libmutter-wayland.la +testgradient_LDADD = $(MUTTER_LIBS) libmutter-wayland.la +testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter-wayland.la @INTLTOOL_DESKTOP_RULE@ desktopfilesdir=$(datadir)/applications -desktopfiles_in_files=mutter.desktop.in +desktopfiles_in_files=mutter-wayland.desktop.in desktopfiles_files=$(desktopfiles_in_files:.desktop.in=.desktop) desktopfiles_DATA = $(desktopfiles_files) -wmpropertiesdir=$(datadir)/gnome/wm-properties -wmproperties_in_files=mutter-wm.desktop.in -wmproperties_files=$(wmproperties_in_files:.desktop.in=.desktop) -wmproperties_DATA = $(wmproperties_files) - xmldir = @GNOME_KEYBINDINGS_KEYSDIR@ xml_in_files = \ 50-mutter-navigation.xml.in \ @@ -282,7 +355,9 @@ xml_in_files = \ 50-mutter-windows.xml.in xml_DATA = $(xml_in_files:.xml.in=.xml) -gsettings_SCHEMAS = org.gnome.mutter.gschema.xml +dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h + +gsettings_SCHEMAS = org.gnome.mutter.gschema.xml org.gnome.mutter.wayland.gschema.xml @INTLTOOL_XML_NOMERGE_RULE@ @GSETTINGS_RULES@ @@ -290,9 +365,10 @@ convertdir = $(datadir)/GConf/gsettings convert_DATA = mutter-schemas.convert CLEANFILES = \ - mutter.desktop \ + mutter-wayland.desktop \ mutter-wm.desktop \ org.gnome.mutter.gschema.xml \ + org.gnome.mutter.wayland.gschema.xml \ $(xml_DATA) \ $(mutter_built_sources) \ $(typelib_DATA) \ @@ -300,7 +376,7 @@ CLEANFILES = \ pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libmutter.pc mutter-plugins.pc +pkgconfig_DATA = libmutter-wayland.pc EXTRA_DIST=$(desktopfiles_files) \ $(wmproperties_files) \ @@ -308,14 +384,15 @@ EXTRA_DIST=$(desktopfiles_files) \ $(desktopfiles_in_files) \ $(wmproperties_in_files) \ $(xml_in_files) \ + $(wayland_protocols) \ org.gnome.mutter.gschema.xml.in \ - idle-monitor.xml \ - xrandr.xml \ + org.gnome.mutter.wayland.gschema.xml.in \ mutter-schemas.convert \ - libmutter.pc.in \ - mutter-plugins.pc.in \ + libmutter-wayland.pc.in \ mutter-enum-types.h.in \ - mutter-enum-types.c.in + mutter-enum-types.c.in \ + org.gnome.Mutter.DisplayConfig.xml \ + org.gnome.Mutter.IdleMonitor.xml BUILT_SOURCES = $(mutter_built_sources) MUTTER_STAMP_FILES = stamp-mutter-enum-types.h @@ -340,21 +417,24 @@ mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in cp xgen-tetc mutter-enum-types.c && \ rm -f xgen-tetc -dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h +dbus_display_config_built_sources = meta-dbus-display-config.c meta-dbus-display-config.h -$(dbus_xrandr_built_sources) : Makefile.am xrandr.xml +$(dbus_display_config_built_sources) : Makefile.am org.gnome.Mutter.DisplayConfig.xml $(AM_V_GEN)gdbus-codegen \ --interface-prefix org.gnome.Mutter \ --c-namespace MetaDBus \ - --generate-c-code meta-dbus-xrandr \ - $(srcdir)/xrandr.xml + --generate-c-code meta-dbus-display-config \ + $(srcdir)/org.gnome.Mutter.DisplayConfig.xml -dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h - -$(dbus_idle_built_sources) : Makefile.am idle-monitor.xml +$(dbus_idle_built_sources) : Makefile.am org.gnome.Mutter.IdleMonitor.xml $(AM_V_GEN)gdbus-codegen \ --interface-prefix org.gnome.Mutter \ --c-namespace MetaDBus \ --generate-c-code meta-dbus-idle-monitor \ --c-generate-object-manager \ - $(srcdir)/idle-monitor.xml + $(srcdir)/org.gnome.Mutter.IdleMonitor.xml + +%-protocol.c : $(srcdir)/wayland/protocol/%.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ +%-server-protocol.h : $(srcdir)/wayland/protocol/%.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@ diff --git a/src/core/edid-parse.c b/src/backends/edid-parse.c index 5b3283a..5b3283a 100644 --- a/src/core/edid-parse.c +++ b/src/backends/edid-parse.c diff --git a/src/core/edid.h b/src/backends/edid.h index 703c639..703c639 100644 --- a/src/core/edid.h +++ b/src/backends/edid.h diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c new file mode 100644 index 0000000..b8a6dc1 --- /dev/null +++ b/src/backends/meta-backend.c @@ -0,0 +1,157 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#include "config.h" + +#include "meta-backend.h" +#include <meta/main.h> + +#include <gdk/gdkx.h> +#include <clutter/clutter.h> +#include <clutter/x11/clutter-x11.h> + +#include "backends/native/meta-weston-launch.h" +#include <meta/util.h> + +/* Mutter is responsible for pulling events off the X queue, so Clutter + * doesn't need (and shouldn't) run its normal event source which polls + * the X fd, but we do have to deal with dispatching events that accumulate + * in the clutter queue. This happens, for example, when clutter generate + * enter/leave events on mouse motion - several events are queued in the + * clutter queue but only one dispatched. It could also happen because of + * explicit calls to clutter_event_put(). We add a very simple custom + * event loop source which is simply responsible for pulling events off + * of the queue and dispatching them before we block for new events. + */ + +static gboolean +event_prepare (GSource *source, + gint *timeout_) +{ + *timeout_ = -1; + + return clutter_events_pending (); +} + +static gboolean +event_check (GSource *source) +{ + return clutter_events_pending (); +} + +static gboolean +event_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + ClutterEvent *event = clutter_event_get (); + + if (event) + { + clutter_do_event (event); + clutter_event_free (event); + } + + return TRUE; +} + +static GSourceFuncs event_funcs = { + event_prepare, + event_check, + event_dispatch +}; + +static MetaLauncher *launcher; + +void +meta_clutter_init (void) +{ + GSource *source; + + /* When running as an X11 compositor, we install our own event filter and + * pass events to Clutter explicitly, so we need to prevent Clutter from + * handling our events. + * + * However, when running as a Wayland compostior under X11 nested, Clutter + * Clutter needs to see events related to its own window. We need to + * eventually replace this with a proper frontend / backend split: Clutter + * under nested is connecting to the "host X server" to get its events it + * needs to put up a window, and GTK+ is connecting to the "inner X server". + * The two would the same in the X11 compositor case, but not when running + * XWayland as a Wayland compositor. + */ + if (!meta_is_wayland_compositor ()) + { + clutter_x11_set_display (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); + clutter_x11_disable_event_retrieval (); + } + + /* If we're running on bare metal, we're a display server, + * so start talking to weston-launch. */ +#if defined(CLUTTER_WINDOWING_EGL) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + launcher = meta_launcher_new (); +#endif + + if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS) + g_error ("Unable to initialize Clutter.\n"); + + source = g_source_new (&event_funcs, sizeof (GSource)); + g_source_attach (source, NULL); + g_source_unref (source); +} + +gboolean +meta_activate_vt (int vt, GError **error) +{ + if (launcher) + return meta_launcher_activate_vt (launcher, vt, error); + else + { + g_debug ("Ignoring VT switch keybinding, not running as display server"); + return TRUE; + } +} + +/** + * meta_activate_session: + * + * Tells mutter to activate the session. When mutter is a + * Wayland compositor, this tells logind to switch over to + * the new session. + */ +gboolean +meta_activate_session (void) +{ + GError *error = NULL; + + if (!meta_launcher_activate_vt (launcher, -1, &error)) + { + g_warning ("Could not activate session: %s\n", error->message); + g_error_free (error); + return FALSE; + } + + return TRUE; +} diff --git a/src/backends/meta-backend.h b/src/backends/meta-backend.h new file mode 100644 index 0000000..03d8a56 --- /dev/null +++ b/src/backends/meta-backend.h @@ -0,0 +1,34 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#ifndef META_BACKEND_H +#define META_BACKEND_H + +#include <glib-object.h> + +void meta_clutter_init (void); + +gboolean meta_activate_vt (int vt, GError **error); + +#endif /* META_BACKEND_H */ diff --git a/src/backends/meta-cursor-private.h b/src/backends/meta-cursor-private.h new file mode 100644 index 0000000..b149021 --- /dev/null +++ b/src/backends/meta-cursor-private.h @@ -0,0 +1,50 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Giovanni Campagna <gcampagn@redhat.com> + */ + +#ifndef META_CURSOR_PRIVATE_H +#define META_CURSOR_PRIVATE_H + +#include "meta-cursor.h" + +#include <cogl/cogl.h> +#include <gbm.h> + +typedef struct { + CoglTexture2D *texture; + struct gbm_bo *bo; + int hot_x, hot_y; +} MetaCursorImage; + +struct _MetaCursorReference { + int ref_count; + + MetaCursorImage image; +}; + +CoglTexture *meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor, + int *hot_x, + int *hot_y); + +struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor, + int *hot_x, + int *hot_y); + +#endif /* META_CURSOR_PRIVATE_H */ diff --git a/src/backends/meta-cursor-tracker-private.h b/src/backends/meta-cursor-tracker-private.h new file mode 100644 index 0000000..ef8de4b --- /dev/null +++ b/src/backends/meta-cursor-tracker-private.h @@ -0,0 +1,98 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Giovanni Campagna <gcampagn@redhat.com> + */ + +#ifndef META_CURSOR_TRACKER_PRIVATE_H +#define META_CURSOR_TRACKER_PRIVATE_H + +#include <meta/meta-cursor-tracker.h> +#include <wayland-server.h> + +#include "meta-cursor.h" + +struct _MetaCursorTracker { + GObject parent_instance; + + MetaScreen *screen; + + gboolean is_showing; + gboolean has_hw_cursor; + + /* The cursor tracker stores the cursor for the current grab + * operation, the cursor for the window with pointer focus, and + * the cursor for the root window, which contains either the + * default arrow cursor or the 'busy' hourglass if we're launching + * an app. + * + * We choose the first one available -- if there's a grab cursor, + * we choose that cursor, if there's window cursor, we choose that, + * otherwise we choose the root cursor. + * + * The displayed_cursor contains the chosen cursor. + */ + MetaCursorReference *displayed_cursor; + + MetaCursorReference *grab_cursor; + + /* Wayland clients can set a NULL buffer as their cursor + * explicitly, which means that we shouldn't display anything. + * So, we can't simply store a NULL in window_cursor to + * determine an unset window cursor; we need an extra boolean. + */ + gboolean has_window_cursor; + MetaCursorReference *window_cursor; + + MetaCursorReference *root_cursor; + + MetaCursorReference *theme_cursors[META_CURSOR_LAST]; + + int current_x, current_y; + MetaRectangle current_rect; + MetaRectangle previous_rect; + gboolean previous_is_valid; + + CoglPipeline *pipeline; + int drm_fd; + struct gbm_device *gbm; +}; + +struct _MetaCursorTrackerClass { + GObjectClass parent_class; +}; + +gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, + XEvent *xevent); + +void meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor); +void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor); +void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker); +void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor); + +void meta_cursor_tracker_update_position (MetaCursorTracker *tracker, + int new_x, + int new_y); +void meta_cursor_tracker_paint (MetaCursorTracker *tracker); + +void meta_cursor_tracker_force_update (MetaCursorTracker *tracker); + +#endif diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c new file mode 100644 index 0000000..28a6af2 --- /dev/null +++ b/src/backends/meta-cursor-tracker.c @@ -0,0 +1,738 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Giovanni Campagna <gcampagn@redhat.com> + */ + +/** + * SECTION:cursor-tracker + * @title: MetaCursorTracker + * @short_description: Mutter cursor tracking helper. Originally only + * tracking the cursor image, now more of a "core + * pointer abstraction" + */ + +#include <config.h> +#include <string.h> +#include <meta/main.h> +#include <meta/util.h> +#include <meta/errors.h> + +#include <cogl/cogl.h> +#include <cogl/cogl-wayland-server.h> +#include <clutter/clutter.h> +#include <gbm.h> + +#include <gdk/gdk.h> +#include <gdk/gdkx.h> + +#include "meta-cursor-private.h" +#include "meta-cursor-tracker-private.h" +#include "screen-private.h" +#include "meta-monitor-manager.h" + +#include "wayland/meta-wayland-private.h" + +G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT); + +enum { + CURSOR_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker, + MetaCRTC *crtc, + gboolean has_hw_cursor); +static void sync_cursor (MetaCursorTracker *tracker); + +static void +meta_cursor_tracker_init (MetaCursorTracker *self) +{ + /* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of + detecting if the system mouse cursor is showing or not. + + On wayland we start with the cursor showing + */ + self->is_showing = TRUE; +} + +static void +meta_cursor_tracker_finalize (GObject *object) +{ + MetaCursorTracker *self = META_CURSOR_TRACKER (object); + int i; + + if (self->displayed_cursor) + meta_cursor_reference_unref (self->displayed_cursor); + if (self->root_cursor) + meta_cursor_reference_unref (self->root_cursor); + + for (i = 0; i < META_CURSOR_LAST; i++) + if (self->theme_cursors[i]) + meta_cursor_reference_unref (self->theme_cursors[i]); + + if (self->pipeline) + cogl_object_unref (self->pipeline); + if (self->gbm) + gbm_device_destroy (self->gbm); + + G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object); +} + +static void +meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_cursor_tracker_finalize; + + signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +static void +on_monitors_changed (MetaMonitorManager *monitors, + MetaCursorTracker *tracker) +{ + MetaCRTC *crtcs; + unsigned int i, n_crtcs; + + if (!tracker->has_hw_cursor) + return; + + /* Go through the new list of monitors, find out where the cursor is */ + meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); + + for (i = 0; i < n_crtcs; i++) + { + MetaRectangle *rect = &crtcs[i].rect; + gboolean has; + + has = meta_rectangle_overlap (&tracker->current_rect, rect); + + /* Need to do it unconditionally here, our tracking is + wrong because we reloaded the CRTCs */ + meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has); + } +} + +static MetaCursorTracker * +make_wayland_cursor_tracker (MetaScreen *screen) +{ + MetaWaylandCompositor *compositor; + CoglContext *ctx; + MetaMonitorManager *monitors; + MetaCursorTracker *self; + + self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL); + self->screen = screen; + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + self->pipeline = cogl_pipeline_new (ctx); + + compositor = meta_wayland_compositor_get_default (); + compositor->seat->cursor_tracker = self; + meta_cursor_tracker_update_position (self, + wl_fixed_to_int (compositor->seat->pointer.x), + wl_fixed_to_int (compositor->seat->pointer.y)); + +#if defined(CLUTTER_WINDOWING_EGL) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + { + CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx)); + self->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer); + self->gbm = gbm_create_device (self->drm_fd); + } +#endif + + monitors = meta_monitor_manager_get (); + g_signal_connect_object (monitors, "monitors-changed", + G_CALLBACK (on_monitors_changed), self, 0); + + return self; +} + +static MetaCursorTracker * +make_x11_cursor_tracker (MetaScreen *screen) +{ + MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL); + self->screen = screen; + + XFixesSelectCursorInput (screen->display->xdisplay, + screen->xroot, + XFixesDisplayCursorNotifyMask); + + return self; +} + +/** + * meta_cursor_tracker_get_for_screen: + * @screen: the #MetaScreen + * + * Retrieves the cursor tracker object for @screen. + * + * Returns: (transfer none): + */ +MetaCursorTracker * +meta_cursor_tracker_get_for_screen (MetaScreen *screen) +{ + MetaCursorTracker *self; + + if (screen->cursor_tracker) + return screen->cursor_tracker; + + if (meta_is_wayland_compositor ()) + self = make_wayland_cursor_tracker (screen); + else + self = make_x11_cursor_tracker (screen); + + screen->cursor_tracker = self; + return self; +} + +static void +set_window_cursor (MetaCursorTracker *tracker, + gboolean has_cursor, + MetaCursorReference *cursor) +{ + g_clear_pointer (&tracker->window_cursor, meta_cursor_reference_unref); + if (cursor) + tracker->window_cursor = meta_cursor_reference_ref (cursor); + tracker->has_window_cursor = has_cursor; + sync_cursor (tracker); +} + +gboolean +meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, + XEvent *xevent) +{ + XFixesCursorNotifyEvent *notify_event; + + if (meta_is_wayland_compositor ()) + return FALSE; + + if (xevent->xany.type != tracker->screen->display->xfixes_event_base + XFixesCursorNotify) + return FALSE; + + notify_event = (XFixesCursorNotifyEvent *)xevent; + if (notify_event->subtype != XFixesDisplayCursorNotify) + return FALSE; + + set_window_cursor (tracker, FALSE, NULL); + + return TRUE; +} + +static MetaCursorReference * +meta_cursor_reference_take_texture (CoglTexture2D *texture, + int hot_x, + int hot_y) +{ + MetaCursorReference *self; + + self = g_slice_new0 (MetaCursorReference); + self->ref_count = 1; + self->image.texture = texture; + self->image.hot_x = hot_x; + self->image.hot_y = hot_y; + + return self; +} + +static void +ensure_xfixes_cursor (MetaCursorTracker *tracker) +{ + XFixesCursorImage *cursor_image; + CoglTexture2D *sprite; + guint8 *cursor_data; + gboolean free_cursor_data; + CoglContext *ctx; + + if (tracker->has_window_cursor) + return; + + cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay); + if (!cursor_image) + return; + + /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit + * quantities as arrays of long; we need to convert on 64 bit */ + if (sizeof(long) == 4) + { + cursor_data = (guint8 *)cursor_image->pixels; + free_cursor_data = FALSE; + } + else + { + int i, j; + guint32 *cursor_words; + gulong *p; + guint32 *q; + + cursor_words = g_new (guint32, cursor_image->width * cursor_image->height); + cursor_data = (guint8 *)cursor_words; + + p = cursor_image->pixels; + q = cursor_words; + for (j = 0; j < cursor_image->height; j++) + for (i = 0; i < cursor_image->width; i++) + *(q++) = *(p++); + + free_cursor_data = TRUE; + } + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + sprite = cogl_texture_2d_new_from_data (ctx, + cursor_image->width, + cursor_image->height, + CLUTTER_CAIRO_FORMAT_ARGB32, + cursor_image->width * 4, /* stride */ + cursor_data, + NULL); + + if (free_cursor_data) + g_free (cursor_data); + + if (sprite != NULL) + { + MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite, + cursor_image->xhot, + cursor_image->yhot); + set_window_cursor (tracker, TRUE, cursor); + } + XFree (cursor_image); +} + +/** + * meta_cursor_tracker_get_sprite: + * + * Returns: (transfer none): + */ +CoglTexture * +meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker) +{ + g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL); + + if (!meta_is_wayland_compositor ()) + ensure_xfixes_cursor (tracker); + + if (tracker->displayed_cursor) + return meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, NULL, NULL); + else + return NULL; +} + +/** + * meta_cursor_tracker_get_hot: + * @tracker: + * @x: (out): + * @y: (out): + * + */ +void +meta_cursor_tracker_get_hot (MetaCursorTracker *tracker, + int *x, + int *y) +{ + g_return_if_fail (META_IS_CURSOR_TRACKER (tracker)); + + if (!meta_is_wayland_compositor ()) + ensure_xfixes_cursor (tracker); + + if (tracker->displayed_cursor) + meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, x, y); + else + { + if (x) + *x = 0; + if (y) + *y = 0; + } +} + +void +meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor) +{ + g_clear_pointer (&tracker->grab_cursor, meta_cursor_reference_unref); + if (cursor) + tracker->grab_cursor = meta_cursor_reference_ref (cursor); + + sync_cursor (tracker); +} + +void +meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor) +{ + set_window_cursor (tracker, TRUE, cursor); +} + +void +meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker) +{ + set_window_cursor (tracker, FALSE, NULL); +} + +void +meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor) +{ + g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref); + if (cursor) + tracker->root_cursor = meta_cursor_reference_ref (cursor); + + sync_cursor (tracker); +} + +static gboolean +should_have_hw_cursor (MetaCursorTracker *tracker) +{ + if (tracker->displayed_cursor) + return (meta_cursor_reference_get_gbm_bo (tracker->displayed_cursor, NULL, NULL) != NULL); + else + return FALSE; +} + +static void +update_hw_cursor (MetaCursorTracker *tracker) +{ + MetaMonitorManager *monitors; + MetaCRTC *crtcs; + unsigned int i, n_crtcs; + gboolean enabled; + + enabled = should_have_hw_cursor (tracker); + tracker->has_hw_cursor = enabled; + + monitors = meta_monitor_manager_get (); + meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); + + for (i = 0; i < n_crtcs; i++) + { + MetaRectangle *rect = &crtcs[i].rect; + gboolean has; + + has = enabled && meta_rectangle_overlap (&tracker->current_rect, rect); + + if (has || crtcs[i].has_hw_cursor) + meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has); + } +} + +static void +move_hw_cursor (MetaCursorTracker *tracker) +{ + MetaMonitorManager *monitors; + MetaCRTC *crtcs; + unsigned int i, n_crtcs; + + monitors = meta_monitor_manager_get (); + meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); + + g_assert (tracker->has_hw_cursor); + + for (i = 0; i < n_crtcs; i++) + { + MetaRectangle *rect = &crtcs[i].rect; + gboolean has; + + has = meta_rectangle_overlap (&tracker->current_rect, rect); + + if (has != crtcs[i].has_hw_cursor) + meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has); + if (has) + drmModeMoveCursor (tracker->drm_fd, crtcs[i].crtc_id, + tracker->current_rect.x - rect->x, + tracker->current_rect.y - rect->y); + } +} + +static MetaCursorReference * +get_displayed_cursor (MetaCursorTracker *tracker) +{ + if (!tracker->is_showing) + return NULL; + + if (tracker->grab_cursor) + return tracker->grab_cursor; + + if (tracker->has_window_cursor) + return tracker->window_cursor; + + return tracker->root_cursor; +} + +static void +update_displayed_cursor (MetaCursorTracker *tracker) +{ + if (meta_is_wayland_compositor ()) + { + if (tracker->displayed_cursor) + { + CoglTexture *texture = meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, NULL, NULL); + cogl_pipeline_set_layer_texture (tracker->pipeline, 0, texture); + } + else + cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL); + + update_hw_cursor (tracker); + } +} + +static void +sync_displayed_cursor (MetaCursorTracker *tracker) +{ + MetaCursorReference *displayed_cursor = get_displayed_cursor (tracker); + + if (tracker->displayed_cursor == displayed_cursor) + return; + + g_clear_pointer (&tracker->displayed_cursor, meta_cursor_reference_unref); + if (displayed_cursor) + tracker->displayed_cursor = meta_cursor_reference_ref (displayed_cursor); + + update_displayed_cursor (tracker); + g_signal_emit (tracker, signals[CURSOR_CHANGED], 0); +} + +static void +meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker) +{ + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + ClutterActor *stage = compositor->stage; + cairo_rectangle_int_t clip; + + g_assert (meta_is_wayland_compositor ()); + + /* Clear the location the cursor was at before, if we need to. */ + if (tracker->previous_is_valid) + { + clip.x = tracker->previous_rect.x; + clip.y = tracker->previous_rect.y; + clip.width = tracker->previous_rect.width; + clip.height = tracker->previous_rect.height; + clutter_actor_queue_redraw_with_clip (stage, &clip); + tracker->previous_is_valid = FALSE; + } + + if (tracker->has_hw_cursor || !tracker->displayed_cursor) + return; + + clip.x = tracker->current_rect.x; + clip.y = tracker->current_rect.y; + clip.width = tracker->current_rect.width; + clip.height = tracker->current_rect.height; + clutter_actor_queue_redraw_with_clip (stage, &clip); +} + +static void +sync_cursor (MetaCursorTracker *tracker) +{ + MetaCursorReference *displayed_cursor; + + sync_displayed_cursor (tracker); + displayed_cursor = tracker->displayed_cursor; + + if (displayed_cursor) + { + CoglTexture *texture; + int hot_x, hot_y; + + texture = meta_cursor_reference_get_cogl_texture (displayed_cursor, &hot_x, &hot_y); + + tracker->current_rect.x = tracker->current_x - hot_x; + tracker->current_rect.y = tracker->current_y - hot_y; + tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture)); + tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture)); + } + else + { + tracker->current_rect.x = 0; + tracker->current_rect.y = 0; + tracker->current_rect.width = 0; + tracker->current_rect.height = 0; + } + + if (meta_is_wayland_compositor ()) + { + if (tracker->has_hw_cursor) + move_hw_cursor (tracker); + else + meta_cursor_tracker_queue_redraw (tracker); + } +} + +void +meta_cursor_tracker_update_position (MetaCursorTracker *tracker, + int new_x, + int new_y) +{ + g_assert (meta_is_wayland_compositor ()); + + tracker->current_x = new_x; + tracker->current_y = new_y; + + sync_cursor (tracker); +} + +void +meta_cursor_tracker_paint (MetaCursorTracker *tracker) +{ + g_assert (meta_is_wayland_compositor ()); + + if (tracker->has_hw_cursor || !tracker->displayed_cursor) + return; + + cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (), + tracker->pipeline, + tracker->current_rect.x, + tracker->current_rect.y, + tracker->current_rect.x + + tracker->current_rect.width, + tracker->current_rect.y + + tracker->current_rect.height); + + tracker->previous_rect = tracker->current_rect; + tracker->previous_is_valid = TRUE; +} + +static void +meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker, + MetaCRTC *crtc, + gboolean has) +{ + if (has) + { + MetaCursorReference *displayed_cursor = tracker->displayed_cursor; + struct gbm_bo *bo; + union gbm_bo_handle handle; + int width, height; + int hot_x, hot_y; + + bo = meta_cursor_reference_get_gbm_bo (displayed_cursor, &hot_x, &hot_y); + + handle = gbm_bo_get_handle (bo); + width = gbm_bo_get_width (bo); + height = gbm_bo_get_height (bo); + + drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, handle.u32, + width, height, hot_x, hot_y); + crtc->has_hw_cursor = TRUE; + } + else + { + drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0); + crtc->has_hw_cursor = FALSE; + } +} + +static void +get_pointer_position_gdk (int *x, + int *y, + int *mods) +{ + GdkDeviceManager *gmanager; + GdkDevice *gdevice; + GdkScreen *gscreen; + + gmanager = gdk_display_get_device_manager (gdk_display_get_default ()); + gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID); + + gdk_device_get_position (gdevice, &gscreen, x, y); + if (mods) + gdk_device_get_state (gdevice, + gdk_screen_get_root_window (gscreen), + NULL, (GdkModifierType*)mods); +} + +static void +get_pointer_position_clutter (int *x, + int *y, + int *mods) +{ + ClutterDeviceManager *cmanager; + ClutterInputDevice *cdevice; + ClutterPoint point; + + cmanager = clutter_device_manager_get_default (); + cdevice = clutter_device_manager_get_core_device (cmanager, CLUTTER_POINTER_DEVICE); + + clutter_input_device_get_coords (cdevice, NULL, &point); + if (x) + *x = point.x; + if (y) + *y = point.y; + if (mods) + *mods = clutter_input_device_get_modifier_state (cdevice); +} + +void +meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker, + int *x, + int *y, + ClutterModifierType *mods) +{ + /* We can't use the clutter interface when not running as a wayland compositor, + because we need to query the server, rather than using the last cached value. + OTOH, on wayland we can't use GDK, because that only sees the events + we forward to xwayland. + */ + if (meta_is_wayland_compositor ()) + get_pointer_position_clutter (x, y, (int*)mods); + else + get_pointer_position_gdk (x, y, (int*)mods); +} + +void +meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker, + gboolean visible) +{ + if (visible == tracker->is_showing) + return; + tracker->is_showing = visible; + + if (meta_is_wayland_compositor ()) + { + sync_cursor (tracker); + } + else + { + if (visible) + XFixesShowCursor (tracker->screen->display->xdisplay, + tracker->screen->xroot); + else + XFixesHideCursor (tracker->screen->display->xdisplay, + tracker->screen->xroot); + } +} + +void +meta_cursor_tracker_force_update (MetaCursorTracker *tracker) +{ + g_assert (meta_is_wayland_compositor ()); + + update_hw_cursor (tracker); + sync_cursor (tracker); +} diff --git a/src/backends/meta-cursor.c b/src/backends/meta-cursor.c new file mode 100644 index 0000000..2a78328 --- /dev/null +++ b/src/backends/meta-cursor.c @@ -0,0 +1,412 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Giovanni Campagna <gcampagn@redhat.com> + */ + +#include "config.h" + +#include "meta-cursor-private.h" + +#include <meta/errors.h> + +#include "display-private.h" +#include "screen-private.h" +#include "meta-cursor-tracker-private.h" /* for tracker->gbm */ + +#include <string.h> + +#include <X11/cursorfont.h> +#include <X11/extensions/Xfixes.h> +#include <X11/Xcursor/Xcursor.h> + +#include <cogl/cogl-wayland-server.h> + +MetaCursorReference * +meta_cursor_reference_ref (MetaCursorReference *self) +{ + g_assert (self->ref_count > 0); + self->ref_count++; + + return self; +} + +static void +meta_cursor_image_free (MetaCursorImage *image) +{ + cogl_object_unref (image->texture); + if (image->bo) + gbm_bo_destroy (image->bo); +} + +static void +meta_cursor_reference_free (MetaCursorReference *self) +{ + meta_cursor_image_free (&self->image); + g_slice_free (MetaCursorReference, self); +} + +void +meta_cursor_reference_unref (MetaCursorReference *self) +{ + self->ref_count--; + + if (self->ref_count == 0) + meta_cursor_reference_free (self); +} + +static void +translate_meta_cursor (MetaCursor cursor, + guint *glyph_out, + const char **name_out) +{ + guint glyph = XC_num_glyphs; + const char *name = NULL; + + switch (cursor) + { + case META_CURSOR_DEFAULT: + glyph = XC_left_ptr; + break; + case META_CURSOR_NORTH_RESIZE: + glyph = XC_top_side; + break; + case META_CURSOR_SOUTH_RESIZE: + glyph = XC_bottom_side; + break; + case META_CURSOR_WEST_RESIZE: + glyph = XC_left_side; + break; + case META_CURSOR_EAST_RESIZE: + glyph = XC_right_side; + break; + case META_CURSOR_SE_RESIZE: + glyph = XC_bottom_right_corner; + break; + case META_CURSOR_SW_RESIZE: + glyph = XC_bottom_left_corner; + break; + case META_CURSOR_NE_RESIZE: + glyph = XC_top_right_corner; + break; + case META_CURSOR_NW_RESIZE: + glyph = XC_top_left_corner; + break; + case META_CURSOR_MOVE_OR_RESIZE_WINDOW: + glyph = XC_fleur; + break; + case META_CURSOR_BUSY: + glyph = XC_watch; + break; + case META_CURSOR_DND_IN_DRAG: + name = "dnd-none"; + break; + case META_CURSOR_DND_MOVE: + name = "dnd-move"; + break; + case META_CURSOR_DND_COPY: + name = "dnd-copy"; + break; + case META_CURSOR_DND_UNSUPPORTED_TARGET: + name = "dnd-none"; + break; + case META_CURSOR_POINTING_HAND: + glyph = XC_hand2; + break; + case META_CURSOR_CROSSHAIR: + glyph = XC_crosshair; + break; + case META_CURSOR_IBEAM: + glyph = XC_xterm; + break; + + default: + g_assert_not_reached (); + glyph = 0; /* silence compiler */ + break; + } + + *glyph_out = glyph; + *name_out = name; +} + +static Cursor +load_cursor_on_server (MetaDisplay *display, + MetaCursor cursor) +{ + Cursor xcursor; + guint glyph; + const char *name; + + translate_meta_cursor (cursor, &glyph, &name); + + if (name != NULL) + xcursor = XcursorLibraryLoadCursor (display->xdisplay, name); + else + xcursor = XCreateFontCursor (display->xdisplay, glyph); + + return xcursor; +} + +Cursor +meta_display_create_x_cursor (MetaDisplay *display, + MetaCursor cursor) +{ + return load_cursor_on_server (display, cursor); +} + +static XcursorImage * +load_cursor_on_client (MetaDisplay *display, + MetaCursor cursor) +{ + XcursorImage *image; + guint glyph; + const char *name; + const char *theme = XcursorGetTheme (display->xdisplay); + int size = XcursorGetDefaultSize (display->xdisplay); + + translate_meta_cursor (cursor, &glyph, &name); + + if (name != NULL) + image = XcursorLibraryLoadImage (name, theme, size); + else + image = XcursorShapeLoadImage (glyph, theme, size); + + return image; +} + +static void +meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm, + MetaCursorImage *image, + uint8_t *pixels, + int width, + int height, + int rowstride, + uint32_t gbm_format) +{ + if (width > 64 || height > 64) + { + meta_warning ("Invalid theme cursor size (must be at most 64x64)\n"); + return; + } + + if (gbm_device_is_format_supported (gbm, gbm_format, + GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE)) + { + uint8_t buf[4 * 64 * 64]; + int i; + + image->bo = gbm_bo_create (gbm, 64, 64, + gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE); + + memset (buf, 0, sizeof(buf)); + for (i = 0; i < height; i++) + memcpy (buf + i * 4 * 64, pixels + i * rowstride, width * 4); + + gbm_bo_write (image->bo, buf, 64 * 64 * 4); + } + else + meta_warning ("HW cursor for format %d not supported\n", gbm_format); +} + +static void +meta_cursor_image_load_from_xcursor_image (MetaCursorTracker *tracker, + MetaCursorImage *image, + XcursorImage *xc_image) +{ + int width, height, rowstride; + CoglPixelFormat cogl_format; + uint32_t gbm_format; + ClutterBackend *clutter_backend; + CoglContext *cogl_context; + + width = xc_image->width; + height = xc_image->height; + rowstride = width * 4; + + gbm_format = GBM_FORMAT_ARGB8888; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + cogl_format = COGL_PIXEL_FORMAT_BGRA_8888; +#else + cogl_format = COGL_PIXEL_FORMAT_ARGB_8888; +#endif + + image->hot_x = xc_image->xhot; + image->hot_y = xc_image->yhot; + + clutter_backend = clutter_get_default_backend (); + cogl_context = clutter_backend_get_cogl_context (clutter_backend); + image->texture = cogl_texture_2d_new_from_data (cogl_context, + width, height, + cogl_format, + rowstride, + (uint8_t *) xc_image->pixels, + NULL); + + if (tracker->gbm) + meta_cursor_image_load_gbm_buffer (tracker->gbm, + image, + (uint8_t *) xc_image->pixels, + width, height, rowstride, + gbm_format); +} + +MetaCursorReference * +meta_cursor_reference_from_theme (MetaCursorTracker *tracker, + MetaCursor cursor) +{ + MetaCursorReference *self; + XcursorImage *image; + + if (tracker->theme_cursors[cursor]) + return meta_cursor_reference_ref (tracker->theme_cursors[cursor]); + + image = load_cursor_on_client (tracker->screen->display, cursor); + if (!image) + return NULL; + + self = g_slice_new0 (MetaCursorReference); + self->ref_count = 1; + meta_cursor_image_load_from_xcursor_image (tracker, &self->image, image); + + XcursorImageDestroy (image); + return self; +} + +static void +meta_cursor_image_load_from_buffer (MetaCursorTracker *tracker, + MetaCursorImage *image, + struct wl_resource *buffer, + int hot_x, + int hot_y) +{ + ClutterBackend *backend; + CoglContext *cogl_context; + struct wl_shm_buffer *shm_buffer; + uint32_t gbm_format; + int width, height; + + image->hot_x = hot_x; + image->hot_y = hot_y; + + backend = clutter_get_default_backend (); + cogl_context = clutter_backend_get_cogl_context (backend); + + image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL); + + width = cogl_texture_get_width (COGL_TEXTURE (image->texture)); + height = cogl_texture_get_height (COGL_TEXTURE (image->texture)); + + shm_buffer = wl_shm_buffer_get (buffer); + if (shm_buffer) + { + if (tracker->gbm) + { + int rowstride = wl_shm_buffer_get_stride (shm_buffer); + + switch (wl_shm_buffer_get_format (shm_buffer)) + { +#if G_BYTE_ORDER == G_BIG_ENDIAN + case WL_SHM_FORMAT_ARGB8888: + gbm_format = GBM_FORMAT_ARGB8888; + break; + case WL_SHM_FORMAT_XRGB8888: + gbm_format = GBM_FORMAT_XRGB8888; + break; +#else + case WL_SHM_FORMAT_ARGB8888: + gbm_format = GBM_FORMAT_ARGB8888; + break; + case WL_SHM_FORMAT_XRGB8888: + gbm_format = GBM_FORMAT_XRGB8888; + break; +#endif + default: + g_warn_if_reached (); + gbm_format = GBM_FORMAT_ARGB8888; + } + + meta_cursor_image_load_gbm_buffer (tracker->gbm, + image, + (uint8_t *) wl_shm_buffer_get_data (shm_buffer), + width, height, rowstride, + gbm_format); + } + } + else + { + /* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses + that, so themed cursors must be padded with transparent pixels to fill the + overlay. This is trivial if we have CPU access to the data, but it's not + possible if the buffer is in GPU memory (and possibly tiled too), so if we + don't get the right size, we fallback to GL. + */ + if (width != 64 || height != 64) + { + meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n"); + return; + } + + if (tracker->gbm) + { + image->bo = gbm_bo_import (tracker->gbm, GBM_BO_IMPORT_WL_BUFFER, + buffer, GBM_BO_USE_CURSOR_64X64); + if (!image->bo) + meta_warning ("Importing HW cursor from wl_buffer failed\n"); + } + } +} + +MetaCursorReference * +meta_cursor_reference_from_buffer (MetaCursorTracker *tracker, + struct wl_resource *buffer, + int hot_x, + int hot_y) +{ + MetaCursorReference *self; + + self = g_slice_new0 (MetaCursorReference); + self->ref_count = 1; + meta_cursor_image_load_from_buffer (tracker, &self->image, buffer, hot_x, hot_y); + + return self; +} + +CoglTexture * +meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor, + int *hot_x, + int *hot_y) +{ + if (hot_x) + *hot_x = cursor->image.hot_x; + if (hot_y) + *hot_y = cursor->image.hot_y; + return COGL_TEXTURE (cursor->image.texture); +} + +struct gbm_bo * +meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor, + int *hot_x, + int *hot_y) +{ + if (hot_x) + *hot_x = cursor->image.hot_x; + if (hot_y) + *hot_y = cursor->image.hot_y; + return cursor->image.bo; +} diff --git a/src/backends/meta-cursor.h b/src/backends/meta-cursor.h new file mode 100644 index 0000000..50ad086 --- /dev/null +++ b/src/backends/meta-cursor.h @@ -0,0 +1,42 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Giovanni Campagna <gcampagn@redhat.com> + */ + +#ifndef META_CURSOR_H +#define META_CURSOR_H + +typedef struct _MetaCursorReference MetaCursorReference; + +MetaCursorReference * meta_cursor_reference_ref (MetaCursorReference *cursor); +void meta_cursor_reference_unref (MetaCursorReference *cursor); + +#include <meta/meta-cursor-tracker.h> +#include <meta/common.h> +#include <wayland-server.h> + +MetaCursorReference * meta_cursor_reference_from_theme (MetaCursorTracker *tracker, + MetaCursor cursor); + +MetaCursorReference * meta_cursor_reference_from_buffer (MetaCursorTracker *tracker, + struct wl_resource *buffer, + int hot_x, + int hot_y); + +#endif /* META_CURSOR_H */ diff --git a/src/core/meta-xrandr-shared.h b/src/backends/meta-display-config-shared.h index 99e3d98..92665cc 100644 --- a/src/core/meta-xrandr-shared.h +++ b/src/backends/meta-display-config-shared.h @@ -16,7 +16,7 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -/* This file is shared between mutter (src/core/meta-xrandr-shared.h) +/* This file is shared between mutter (src/core/meta-display-config-shared.h) and gnome-desktop (libgnome-desktop/meta-xrandr-shared.h). The canonical place for all changes is mutter. @@ -24,8 +24,8 @@ There should be no includes in this file. */ -#ifndef META_XRANDR_SHARED_H -#define META_XRANDR_SHARED_H +#ifndef META_DISPLAY_CONFIG_SHARED_H +#define META_DISPLAY_CONFIG_SHARED_H typedef enum { META_POWER_SAVE_UNSUPPORTED = -1, @@ -35,4 +35,4 @@ typedef enum { META_POWER_SAVE_OFF, } MetaPowerSave; -#endif +#endif /* META_DISPLAY_CONFIG_SHARED_H */ diff --git a/src/backends/meta-idle-monitor-dbus.c b/src/backends/meta-idle-monitor-dbus.c new file mode 100644 index 0000000..811b46a --- /dev/null +++ b/src/backends/meta-idle-monitor-dbus.c @@ -0,0 +1,286 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#include "config.h" + +#include "meta-idle-monitor-dbus.h" +#include <meta/meta-idle-monitor.h> +#include "meta-dbus-idle-monitor.h" + +#include <clutter/clutter.h> +#include <meta/util.h> +#include <meta/main.h> /* for meta_get_replace_current_wm () */ + +static gboolean +handle_get_idletime (MetaDBusIdleMonitor *skeleton, + GDBusMethodInvocation *invocation, + MetaIdleMonitor *monitor) +{ + guint64 idletime; + + idletime = meta_idle_monitor_get_idletime (monitor); + meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime); + + return TRUE; +} + +typedef struct { + MetaDBusIdleMonitor *dbus_monitor; + MetaIdleMonitor *monitor; + char *dbus_name; + guint watch_id; + guint name_watcher_id; +} DBusWatch; + +static void +destroy_dbus_watch (gpointer data) +{ + DBusWatch *watch = data; + + g_object_unref (watch->dbus_monitor); + g_object_unref (watch->monitor); + g_free (watch->dbus_name); + g_bus_unwatch_name (watch->name_watcher_id); + + g_slice_free (DBusWatch, watch); +} + +static void +dbus_idle_callback (MetaIdleMonitor *monitor, + guint watch_id, + gpointer user_data) +{ + DBusWatch *watch = user_data; + GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor); + + g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton), + watch->dbus_name, + g_dbus_interface_skeleton_get_object_path (skeleton), + "org.gnome.Mutter.IdleMonitor", + "WatchFired", + g_variant_new ("(u)", watch_id), + NULL); +} + +static void +name_vanished_callback (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + DBusWatch *watch = user_data; + + meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id); +} + +static DBusWatch * +make_dbus_watch (MetaDBusIdleMonitor *skeleton, + GDBusMethodInvocation *invocation, + MetaIdleMonitor *monitor) +{ + DBusWatch *watch; + + watch = g_slice_new (DBusWatch); + watch->dbus_monitor = g_object_ref (skeleton); + watch->monitor = g_object_ref (monitor); + watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation)); + watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation), + watch->dbus_name, + G_BUS_NAME_WATCHER_FLAGS_NONE, + NULL, /* appeared */ + name_vanished_callback, + watch, NULL); + + return watch; +} + +static gboolean +handle_add_idle_watch (MetaDBusIdleMonitor *skeleton, + GDBusMethodInvocation *invocation, + guint64 interval, + MetaIdleMonitor *monitor) +{ + DBusWatch *watch; + + watch = make_dbus_watch (skeleton, invocation, monitor); + watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval, + dbus_idle_callback, watch, destroy_dbus_watch); + + meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id); + + return TRUE; +} + +static gboolean +handle_add_user_active_watch (MetaDBusIdleMonitor *skeleton, + GDBusMethodInvocation *invocation, + MetaIdleMonitor *monitor) +{ + DBusWatch *watch; + + watch = make_dbus_watch (skeleton, invocation, monitor); + watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor, + dbus_idle_callback, watch, + destroy_dbus_watch); + + meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id); + + return TRUE; +} + +static gboolean +handle_remove_watch (MetaDBusIdleMonitor *skeleton, + GDBusMethodInvocation *invocation, + guint id, + MetaIdleMonitor *monitor) +{ + meta_idle_monitor_remove_watch (monitor, id); + meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation); + + return TRUE; +} + +static void +create_monitor_skeleton (GDBusObjectManagerServer *manager, + MetaIdleMonitor *monitor, + const char *path) +{ + MetaDBusIdleMonitor *skeleton; + MetaDBusObjectSkeleton *object; + + skeleton = meta_dbus_idle_monitor_skeleton_new (); + g_signal_connect_object (skeleton, "handle-add-idle-watch", + G_CALLBACK (handle_add_idle_watch), monitor, 0); + g_signal_connect_object (skeleton, "handle-add-user-active-watch", + G_CALLBACK (handle_add_user_active_watch), monitor, 0); + g_signal_connect_object (skeleton, "handle-remove-watch", + G_CALLBACK (handle_remove_watch), monitor, 0); + g_signal_connect_object (skeleton, "handle-get-idletime", + G_CALLBACK (handle_get_idletime), monitor, 0); + + object = meta_dbus_object_skeleton_new (path); + meta_dbus_object_skeleton_set_idle_monitor (object, skeleton); + + g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object)); +} + +static void +on_device_added (ClutterDeviceManager *device_manager, + ClutterInputDevice *device, + GDBusObjectManagerServer *manager) +{ + + MetaIdleMonitor *monitor; + int device_id; + char *path; + + device_id = clutter_input_device_get_device_id (device); + monitor = meta_idle_monitor_get_for_device (device_id); + path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id); + + create_monitor_skeleton (manager, monitor, path); + g_free (path); +} + +static void +on_device_removed (ClutterDeviceManager *device_manager, + ClutterInputDevice *device, + GDBusObjectManagerServer *manager) +{ + int device_id; + char *path; + + device_id = clutter_input_device_get_device_id (device); + path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id); + g_dbus_object_manager_server_unexport (manager, path); + g_free (path); +} + +static void +on_bus_acquired (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + GDBusObjectManagerServer *manager; + ClutterDeviceManager *device_manager; + MetaIdleMonitor *monitor; + GSList *devices, *iter; + char *path; + + manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor"); + + /* We never clear the core monitor, as that's supposed to cumulate idle times from + all devices */ + monitor = meta_idle_monitor_get_core (); + path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core"); + create_monitor_skeleton (manager, monitor, path); + g_free (path); + + device_manager = clutter_device_manager_get_default (); + devices = clutter_device_manager_list_devices (device_manager); + + for (iter = devices; iter; iter = iter->next) + on_device_added (device_manager, iter->data, manager); + + g_slist_free (devices); + + g_signal_connect_object (device_manager, "device-added", + G_CALLBACK (on_device_added), manager, 0); + g_signal_connect_object (device_manager, "device-removed", + G_CALLBACK (on_device_removed), manager, 0); + + g_dbus_object_manager_server_set_connection (manager, connection); +} + +static void +on_name_acquired (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + meta_verbose ("Acquired name %s\n", name); +} + +static void +on_name_lost (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + meta_verbose ("Lost or failed to acquire name %s\n", name); +} + +void +meta_idle_monitor_init_dbus (void) +{ + static int dbus_name_id; + + if (dbus_name_id > 0) + return; + + dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION, + "org.gnome.Mutter.IdleMonitor", + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | + (meta_get_replace_current_wm () ? + G_BUS_NAME_OWNER_FLAGS_REPLACE : 0), + on_bus_acquired, + on_name_acquired, + on_name_lost, + NULL, NULL); +} diff --git a/src/core/meta-idle-monitor-private.h b/src/backends/meta-idle-monitor-dbus.h index 6854ebe..a0d703f 100644 --- a/src/core/meta-idle-monitor-private.h +++ b/src/backends/meta-idle-monitor-dbus.h @@ -1,8 +1,8 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* +/* * Copyright 2013 Red Hat, Inc. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the @@ -12,7 +12,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. * @@ -20,9 +20,9 @@ * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c */ -#include <meta/meta-idle-monitor.h> - -void meta_idle_monitor_handle_xevent_all (XEvent *xevent); - +#ifndef META_IDLE_MONITOR_DBUS_H +#define META_IDLE_MONITOR_DBUS_H void meta_idle_monitor_init_dbus (void); + +#endif diff --git a/src/backends/meta-idle-monitor-private.h b/src/backends/meta-idle-monitor-private.h new file mode 100644 index 0000000..ea414e1 --- /dev/null +++ b/src/backends/meta-idle-monitor-private.h @@ -0,0 +1,65 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#ifndef META_IDLE_MONITOR_PRIVATE_H +#define META_IDLE_MONITOR_PRIVATE_H + +#include <meta/meta-idle-monitor.h> +#include "display-private.h" + +#include <X11/Xlib.h> +#include <X11/extensions/sync.h> + +typedef struct +{ + MetaIdleMonitor *monitor; + guint id; + MetaIdleMonitorWatchFunc callback; + gpointer user_data; + GDestroyNotify notify; + guint64 timeout_msec; + int idle_source_id; +} MetaIdleMonitorWatch; + +struct _MetaIdleMonitor +{ + GObject parent_instance; + + GHashTable *watches; + int device_id; +}; + +struct _MetaIdleMonitorClass +{ + GObjectClass parent_class; + + gint64 (*get_idletime) (MetaIdleMonitor *monitor); + MetaIdleMonitorWatch * (*make_watch) (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify); +}; + +void _meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch); + +#endif /* META_IDLE_MONITOR_PRIVATE_H */ diff --git a/src/backends/meta-idle-monitor.c b/src/backends/meta-idle-monitor.c new file mode 100644 index 0000000..4c4357a --- /dev/null +++ b/src/backends/meta-idle-monitor.c @@ -0,0 +1,367 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +/** + * SECTION:idle-monitor + * @title: MetaIdleMonitor + * @short_description: Mutter idle counter (similar to X's IDLETIME) + */ + +#include "config.h" + +#include <string.h> +#include <clutter/clutter.h> +#include <X11/Xlib.h> +#include <X11/extensions/sync.h> + +#include <meta/util.h> +#include <meta/main.h> +#include <meta/meta-idle-monitor.h> +#include "meta-idle-monitor-private.h" +#include "meta-idle-monitor-dbus.h" +#include "backends/x11/meta-idle-monitor-xsync.h" +#include "backends/native/meta-idle-monitor-native.h" + +G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer)); + +enum +{ + PROP_0, + PROP_DEVICE_ID, + PROP_LAST, +}; + +static GParamSpec *obj_props[PROP_LAST]; + +G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT) + +static MetaIdleMonitor *device_monitors[256]; +static int device_id_max; + +void +_meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch) +{ + MetaIdleMonitor *monitor; + guint id; + gboolean is_user_active_watch; + + monitor = watch->monitor; + g_object_ref (monitor); + + if (watch->idle_source_id) + { + g_source_remove (watch->idle_source_id); + watch->idle_source_id = 0; + } + + id = watch->id; + is_user_active_watch = (watch->timeout_msec == 0); + + if (watch->callback) + watch->callback (monitor, id, watch->user_data); + + if (is_user_active_watch) + meta_idle_monitor_remove_watch (monitor, id); + + g_object_unref (monitor); +} + +static void +meta_idle_monitor_dispose (GObject *object) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); + + g_clear_pointer (&monitor->watches, g_hash_table_destroy); + + G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object); +} + +static void +meta_idle_monitor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); + + switch (prop_id) + { + case PROP_DEVICE_ID: + g_value_set_int (value, monitor->device_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +meta_idle_monitor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); + switch (prop_id) + { + case PROP_DEVICE_ID: + monitor->device_id = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +meta_idle_monitor_class_init (MetaIdleMonitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = meta_idle_monitor_dispose; + object_class->get_property = meta_idle_monitor_get_property; + object_class->set_property = meta_idle_monitor_set_property; + + /** + * MetaIdleMonitor:device_id: + * + * The device to listen to idletime on. + */ + obj_props[PROP_DEVICE_ID] = + g_param_spec_int ("device-id", + "Device ID", + "The device to listen to idletime on", + 0, 255, 0, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_DEVICE_ID, obj_props[PROP_DEVICE_ID]); +} + +static void +meta_idle_monitor_init (MetaIdleMonitor *monitor) +{ +} + +static GType +get_idle_monitor_type (void) +{ + if (meta_is_wayland_compositor ()) + return META_TYPE_IDLE_MONITOR_NATIVE; + else + return META_TYPE_IDLE_MONITOR_XSYNC; +} + +static void +ensure_device_monitor (int device_id) +{ + if (device_monitors[device_id]) + return; + + device_monitors[device_id] = g_object_new (get_idle_monitor_type (), + "device-id", device_id, + NULL); + device_id_max = MAX (device_id_max, device_id); +} + +/* FIXME -- destroy device monitors at some point */ +G_GNUC_UNUSED static void +destroy_device_monitor (int device_id) +{ + g_clear_object (&device_monitors[device_id]); + if (device_id == device_id_max) + device_id_max--; +} + +/** + * meta_idle_monitor_get_core: + * + * Returns: (transfer none): the #MetaIdleMonitor that tracks the server-global + * idletime for all devices. To track device-specific idletime, + * use meta_idle_monitor_get_for_device(). + */ +MetaIdleMonitor * +meta_idle_monitor_get_core (void) +{ + ensure_device_monitor (0); + return device_monitors[0]; +} + +/** + * meta_idle_monitor_get_for_device: + * @device_id: the device to get the idle time for. + * + * Returns: (transfer none): a new #MetaIdleMonitor that tracks the + * device-specific idletime for @device. To track server-global idletime + * for all devices, use meta_idle_monitor_get_core(). + */ +MetaIdleMonitor * +meta_idle_monitor_get_for_device (int device_id) +{ + g_return_val_if_fail (device_id > 0 && device_id < 256, NULL); + + ensure_device_monitor (device_id); + return device_monitors[device_id]; +} + +static MetaIdleMonitorWatch * +make_watch (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatch *watch; + + watch = META_IDLE_MONITOR_GET_CLASS (monitor)->make_watch (monitor, + timeout_msec, + callback, + user_data, + notify); + + g_hash_table_insert (monitor->watches, + GUINT_TO_POINTER (watch->id), + watch); + return watch; +} + +/** + * meta_idle_monitor_add_idle_watch: + * @monitor: A #MetaIdleMonitor + * @interval_msec: The idletime interval, in milliseconds + * @callback: (allow-none): The callback to call when the user has + * accumulated @interval_msec milliseconds of idle time. + * @user_data: (allow-none): The user data to pass to the callback + * @notify: A #GDestroyNotify + * + * Returns: a watch id + * + * Adds a watch for a specific idle time. The callback will be called + * when the user has accumulated @interval_msec milliseconds of idle time. + * This function will return an ID that can either be passed to + * meta_idle_monitor_remove_watch(), or can be used to tell idle time + * watches apart if you have more than one. + * + * Also note that this function will only care about positive transitions + * (user's idle time exceeding a certain time). If you want to know about + * when the user has become active, use + * meta_idle_monitor_add_user_active_watch(). + */ +guint +meta_idle_monitor_add_idle_watch (MetaIdleMonitor *monitor, + guint64 interval_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatch *watch; + + g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0); + g_return_val_if_fail (interval_msec > 0, 0); + + watch = make_watch (monitor, + interval_msec, + callback, + user_data, + notify); + + return watch->id; +} + +/** + * meta_idle_monitor_add_user_active_watch: + * @monitor: A #MetaIdleMonitor + * @callback: (allow-none): The callback to call when the user is + * active again. + * @user_data: (allow-none): The user data to pass to the callback + * @notify: A #GDestroyNotify + * + * Returns: a watch id + * + * Add a one-time watch to know when the user is active again. + * Note that this watch is one-time and will de-activate after the + * function is called, for efficiency purposes. It's most convenient + * to call this when an idle watch, as added by + * meta_idle_monitor_add_idle_watch(), has triggered. + */ +guint +meta_idle_monitor_add_user_active_watch (MetaIdleMonitor *monitor, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatch *watch; + + g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0); + + watch = make_watch (monitor, + 0, + callback, + user_data, + notify); + + return watch->id; +} + +/** + * meta_idle_monitor_remove_watch: + * @monitor: A #MetaIdleMonitor + * @id: A watch ID + * + * Removes an idle time watcher, previously added by + * meta_idle_monitor_add_idle_watch() or + * meta_idle_monitor_add_user_active_watch(). + */ +void +meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor, + guint id) +{ + g_return_if_fail (META_IS_IDLE_MONITOR (monitor)); + + g_object_ref (monitor); + g_hash_table_remove (monitor->watches, + GUINT_TO_POINTER (id)); + g_object_unref (monitor); +} + +/** + * meta_idle_monitor_get_idletime: + * @monitor: A #MetaIdleMonitor + * + * Returns: The current idle time, in milliseconds, or -1 for not supported + */ +gint64 +meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor) +{ + return META_IDLE_MONITOR_GET_CLASS (monitor)->get_idletime (monitor); +} + +void +meta_idle_monitor_xsync_handle_xevent_all (XEvent *xevent) +{ + int i; + + if (meta_is_wayland_compositor ()) + return; + + for (i = 0; i <= device_id_max; i++) + if (device_monitors[i]) + meta_idle_monitor_xsync_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent); +} diff --git a/src/core/monitor-config.c b/src/backends/meta-monitor-config.c index a7e4ed5..f7ddce5 100644 --- a/src/core/monitor-config.c +++ b/src/backends/meta-monitor-config.c @@ -34,13 +34,14 @@ #include "config.h" +#include "meta-monitor-config.h" + #include <string.h> #include <clutter/clutter.h> #include <libupower-glib/upower.h> #include <meta/main.h> #include <meta/errors.h> -#include "monitor-private.h" /* These structures represent the intended/persistent configuration, as stored in the monitors.xml file. diff --git a/src/backends/meta-monitor-config.h b/src/backends/meta-monitor-config.h new file mode 100644 index 0000000..8401569 --- /dev/null +++ b/src/backends/meta-monitor-config.h @@ -0,0 +1,55 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef META_MONITOR_CONFIG_H +#define META_MONITOR_CONFIG_H + +#include "meta-monitor-manager.h" + +#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ()) +#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig)) +#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass)) +#define META_IS_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG)) +#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_CONFIG)) +#define META_MONITOR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass)) + +GType meta_monitor_config_get_type (void) G_GNUC_CONST; + +MetaMonitorConfig *meta_monitor_config_new (void); + +gboolean meta_monitor_config_match_current (MetaMonitorConfig *config, + MetaMonitorManager *manager); + +gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config, + MetaMonitorManager *manager); + +void meta_monitor_config_make_default (MetaMonitorConfig *config, + MetaMonitorManager *manager); + +void meta_monitor_config_update_current (MetaMonitorConfig *config, + MetaMonitorManager *manager); +void meta_monitor_config_make_persistent (MetaMonitorConfig *config); + +void meta_monitor_config_restore_previous (MetaMonitorConfig *config, + MetaMonitorManager *manager); + +#endif /* META_MONITOR_CONFIG_H */ diff --git a/src/backends/meta-monitor-manager-dummy.c b/src/backends/meta-monitor-manager-dummy.c new file mode 100644 index 0000000..46cea93 --- /dev/null +++ b/src/backends/meta-monitor-manager-dummy.c @@ -0,0 +1,227 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001, 2002 Havoc Pennington + * Copyright (C) 2002, 2003 Red Hat Inc. + * Some ICCCM manager selection code derived from fvwm2, + * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include "meta-monitor-manager-dummy.h" + +#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1) + +struct _MetaMonitorManagerDummy +{ + MetaMonitorManager parent_instance; +}; + +struct _MetaMonitorManagerDummyClass +{ + MetaMonitorManagerClass parent_class; +}; + +G_DEFINE_TYPE (MetaMonitorManagerDummy, meta_monitor_manager_dummy, META_TYPE_MONITOR_MANAGER); + +static void +meta_monitor_manager_dummy_read_current (MetaMonitorManager *manager) +{ + manager->max_screen_width = 65535; + manager->max_screen_height = 65535; + manager->screen_width = 1024; + manager->screen_height = 768; + + manager->modes = g_new0 (MetaMonitorMode, 1); + manager->n_modes = 1; + + manager->modes[0].mode_id = 0; + manager->modes[0].width = 1024; + manager->modes[0].height = 768; + manager->modes[0].refresh_rate = 60.0; + + manager->crtcs = g_new0 (MetaCRTC, 1); + manager->n_crtcs = 1; + + manager->crtcs[0].crtc_id = 1; + manager->crtcs[0].rect.x = 0; + manager->crtcs[0].rect.y = 0; + manager->crtcs[0].rect.width = manager->modes[0].width; + manager->crtcs[0].rect.height = manager->modes[0].height; + manager->crtcs[0].current_mode = &manager->modes[0]; + manager->crtcs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL; + manager->crtcs[0].all_transforms = ALL_WL_TRANSFORMS; + manager->crtcs[0].is_dirty = FALSE; + manager->crtcs[0].logical_monitor = NULL; + + manager->outputs = g_new0 (MetaOutput, 1); + manager->n_outputs = 1; + + manager->outputs[0].crtc = &manager->crtcs[0]; + manager->outputs[0].output_id = 1; + manager->outputs[0].name = g_strdup ("LVDS"); + manager->outputs[0].vendor = g_strdup ("MetaProducts Inc."); + manager->outputs[0].product = g_strdup ("unknown"); + manager->outputs[0].serial = g_strdup ("0xC0FFEE"); + manager->outputs[0].width_mm = 222; + manager->outputs[0].height_mm = 125; + manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; + manager->outputs[0].preferred_mode = &manager->modes[0]; + manager->outputs[0].n_modes = 1; + manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 1); + manager->outputs[0].modes[0] = &manager->modes[0]; + manager->outputs[0].n_possible_crtcs = 1; + manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 1); + manager->outputs[0].possible_crtcs[0] = &manager->crtcs[0]; + manager->outputs[0].n_possible_clones = 0; + manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0); + manager->outputs[0].backlight = -1; + manager->outputs[0].backlight_min = 0; + manager->outputs[0].backlight_max = 0; +} + +static void +meta_monitor_manager_dummy_apply_config (MetaMonitorManager *manager, + MetaCRTCInfo **crtcs, + unsigned int n_crtcs, + MetaOutputInfo **outputs, + unsigned int n_outputs) +{ + unsigned i; + int screen_width = 0, screen_height = 0; + + for (i = 0; i < n_crtcs; i++) + { + MetaCRTCInfo *crtc_info = crtcs[i]; + MetaCRTC *crtc = crtc_info->crtc; + crtc->is_dirty = TRUE; + + if (crtc_info->mode == NULL) + { + crtc->rect.x = 0; + crtc->rect.y = 0; + crtc->rect.width = 0; + crtc->rect.height = 0; + crtc->current_mode = NULL; + } + else + { + MetaMonitorMode *mode; + MetaOutput *output; + int i, n_outputs; + int width, height; + + mode = crtc_info->mode; + + if (meta_monitor_transform_is_rotated (crtc_info->transform)) + { + width = mode->height; + height = mode->width; + } + else + { + width = mode->width; + height = mode->height; + } + + crtc->rect.x = crtc_info->x; + crtc->rect.y = crtc_info->y; + crtc->rect.width = width; + crtc->rect.height = height; + crtc->current_mode = mode; + crtc->transform = crtc_info->transform; + + screen_width = MAX (screen_width, crtc_info->x + width); + screen_height = MAX (screen_height, crtc_info->y + height); + + n_outputs = crtc_info->outputs->len; + for (i = 0; i < n_outputs; i++) + { + output = ((MetaOutput**)crtc_info->outputs->pdata)[i]; + + output->is_dirty = TRUE; + output->crtc = crtc; + } + } + } + + for (i = 0; i < n_outputs; i++) + { + MetaOutputInfo *output_info = outputs[i]; + MetaOutput *output = output_info->output; + + output->is_primary = output_info->is_primary; + output->is_presentation = output_info->is_presentation; + } + + /* Disable CRTCs not mentioned in the list */ + for (i = 0; i < manager->n_crtcs; i++) + { + MetaCRTC *crtc = &manager->crtcs[i]; + + crtc->logical_monitor = NULL; + + if (crtc->is_dirty) + { + crtc->is_dirty = FALSE; + continue; + } + + crtc->rect.x = 0; + crtc->rect.y = 0; + crtc->rect.width = 0; + crtc->rect.height = 0; + crtc->current_mode = NULL; + } + + /* Disable outputs not mentioned in the list */ + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *output = &manager->outputs[i]; + + if (output->is_dirty) + { + output->is_dirty = FALSE; + continue; + } + + output->crtc = NULL; + output->is_primary = FALSE; + } + + manager->screen_width = screen_width; + manager->screen_height = screen_height; + + meta_monitor_manager_rebuild_derived (manager); +} + +static void +meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass) +{ + MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass); + + manager_class->read_current = meta_monitor_manager_dummy_read_current; + manager_class->apply_configuration = meta_monitor_manager_dummy_apply_config; +} + +static void +meta_monitor_manager_dummy_init (MetaMonitorManagerDummy *manager) +{ +} diff --git a/src/backends/meta-monitor-manager-dummy.h b/src/backends/meta-monitor-manager-dummy.h new file mode 100644 index 0000000..4f1fb34 --- /dev/null +++ b/src/backends/meta-monitor-manager-dummy.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef META_MONITOR_MANAGER_DUMMY_H +#define META_MONITOR_MANAGER_DUMMY_H + +#include "meta-monitor-manager.h" + +#define META_TYPE_MONITOR_MANAGER_DUMMY (meta_monitor_manager_dummy_get_type ()) +#define META_MONITOR_MANAGER_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_DUMMY, MetaMonitorManagerDummy)) +#define META_MONITOR_MANAGER_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_DUMMY, MetaMonitorManagerDummyClass)) +#define META_IS_MONITOR_MANAGER_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_DUMMY)) +#define META_IS_MONITOR_MANAGER_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_DUMMY)) +#define META_MONITOR_MANAGER_DUMMY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_DUMMY, MetaMonitorManagerDummyClass)) + +typedef struct _MetaMonitorManagerDummyClass MetaMonitorManagerDummyClass; +typedef struct _MetaMonitorManagerDummy MetaMonitorManagerDummy; + +GType meta_monitor_manager_dummy_get_type (void); + +#endif /* META_MONITOR_MANAGER_DUMMY_H */ diff --git a/src/core/monitor.c b/src/backends/meta-monitor-manager.c index f006052..a437c5f 100644 --- a/src/core/monitor.c +++ b/src/backends/meta-monitor-manager.c @@ -25,6 +25,8 @@ #include "config.h" +#include "meta-monitor-manager.h" + #include <string.h> #include <math.h> #include <stdlib.h> @@ -33,11 +35,10 @@ #include <meta/main.h> #include "util-private.h" #include <meta/errors.h> -#include "monitor-private.h" - -#include "meta-dbus-xrandr.h" - -#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1) +#include "meta-monitor-config.h" +#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/x11/meta-monitor-manager-xrandr.h" +#include "meta-monitor-manager-dummy.h" enum { CONFIRM_DISPLAY_CHANGE, @@ -54,314 +55,12 @@ static int signals[SIGNALS_LAST]; static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface); -G_DEFINE_TYPE_WITH_CODE (MetaMonitorManager, meta_monitor_manager, META_DBUS_TYPE_DISPLAY_CONFIG_SKELETON, - G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_DISPLAY_CONFIG, meta_monitor_manager_display_config_init)); +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaMonitorManager, meta_monitor_manager, META_DBUS_TYPE_DISPLAY_CONFIG_SKELETON, + G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_DISPLAY_CONFIG, meta_monitor_manager_display_config_init)); static void initialize_dbus_interface (MetaMonitorManager *manager); static void -read_current_dummy (MetaMonitorManager *manager) -{ - /* The dummy monitor config has: - - one enabled output, LVDS, primary, at 0x0 and 1024x768 - - one free CRTC - - two disabled outputs - - three modes, 1024x768, 800x600 and 640x480 - - no clones are possible (use different CRTCs) - - Low-level IDs should be assigned sequentially, to - mimick what XRandR and KMS do - */ - - manager->max_screen_width = 65535; - manager->max_screen_height = 65535; - manager->screen_width = 1024; - manager->screen_height = 768; - - manager->modes = g_new0 (MetaMonitorMode, 6); - manager->n_modes = 6; - - manager->modes[0].mode_id = 1; - manager->modes[0].width = 1024; - manager->modes[0].height = 768; - manager->modes[0].refresh_rate = 60.0; - - manager->modes[1].mode_id = 2; - manager->modes[1].width = 800; - manager->modes[1].height = 600; - manager->modes[1].refresh_rate = 60.0; - - manager->modes[2].mode_id = 3; - manager->modes[2].width = 640; - manager->modes[2].height = 480; - manager->modes[2].refresh_rate = 60.0; - - manager->modes[3].mode_id = 4; - manager->modes[3].width = 1920; - manager->modes[3].height = 1080; - manager->modes[3].refresh_rate = 60.0; - - manager->modes[4].mode_id = 5; - manager->modes[4].width = 1920; - manager->modes[4].height = 1080; - manager->modes[4].refresh_rate = 55.0; - - manager->modes[5].mode_id = 6; - manager->modes[5].width = 1600; - manager->modes[5].height = 900; - manager->modes[5].refresh_rate = 60.0; - - manager->crtcs = g_new0 (MetaCRTC, 3); - manager->n_crtcs = 3; - - manager->crtcs[0].crtc_id = 4; - manager->crtcs[0].rect.x = 0; - manager->crtcs[0].rect.y = 0; - manager->crtcs[0].rect.width = manager->modes[0].width; - manager->crtcs[0].rect.height = manager->modes[0].height; - manager->crtcs[0].current_mode = &manager->modes[0]; - manager->crtcs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL; - manager->crtcs[0].all_transforms = ALL_WL_TRANSFORMS; - manager->crtcs[0].is_dirty = FALSE; - manager->crtcs[0].logical_monitor = NULL; - - manager->crtcs[1].crtc_id = 5; - manager->crtcs[1].rect.x = 0; - manager->crtcs[1].rect.y = 0; - manager->crtcs[1].rect.width = 0; - manager->crtcs[1].rect.height = 0; - manager->crtcs[1].current_mode = NULL; - manager->crtcs[1].transform = WL_OUTPUT_TRANSFORM_NORMAL; - manager->crtcs[1].all_transforms = ALL_WL_TRANSFORMS; - manager->crtcs[1].is_dirty = FALSE; - manager->crtcs[1].logical_monitor = NULL; - - manager->crtcs[2].crtc_id = 5; - manager->crtcs[2].rect.x = 0; - manager->crtcs[2].rect.y = 0; - manager->crtcs[2].rect.width = 0; - manager->crtcs[2].rect.height = 0; - manager->crtcs[2].current_mode = NULL; - manager->crtcs[2].transform = WL_OUTPUT_TRANSFORM_NORMAL; - manager->crtcs[2].all_transforms = ALL_WL_TRANSFORMS; - manager->crtcs[2].is_dirty = FALSE; - manager->crtcs[2].logical_monitor = NULL; - - manager->outputs = g_new0 (MetaOutput, 3); - manager->n_outputs = 3; - - manager->outputs[0].crtc = NULL; - manager->outputs[0].output_id = 6; - manager->outputs[0].name = g_strdup ("HDMI"); - manager->outputs[0].vendor = g_strdup ("MetaProducts Inc."); - manager->outputs[0].product = g_strdup ("unknown"); - manager->outputs[0].serial = g_strdup ("0xC0F01A"); - manager->outputs[0].width_mm = 510; - manager->outputs[0].height_mm = 287; - manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; - manager->outputs[0].preferred_mode = &manager->modes[3]; - manager->outputs[0].n_modes = 5; - manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 5); - manager->outputs[0].modes[0] = &manager->modes[0]; - manager->outputs[0].modes[1] = &manager->modes[1]; - manager->outputs[0].modes[2] = &manager->modes[2]; - manager->outputs[0].modes[3] = &manager->modes[3]; - manager->outputs[0].modes[4] = &manager->modes[4]; - manager->outputs[0].n_possible_crtcs = 3; - manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 3); - manager->outputs[0].possible_crtcs[0] = &manager->crtcs[0]; - manager->outputs[0].possible_crtcs[1] = &manager->crtcs[1]; - manager->outputs[0].possible_crtcs[2] = &manager->crtcs[2]; - manager->outputs[0].n_possible_clones = 0; - manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0); - manager->outputs[0].backlight = -1; - manager->outputs[0].backlight_min = 0; - manager->outputs[0].backlight_max = 0; - - manager->outputs[1].crtc = &manager->crtcs[0]; - manager->outputs[1].output_id = 7; - manager->outputs[1].name = g_strdup ("LVDS"); - manager->outputs[1].vendor = g_strdup ("MetaProducts Inc."); - manager->outputs[1].product = g_strdup ("unknown"); - manager->outputs[1].serial = g_strdup ("0xC0FFEE"); - manager->outputs[1].width_mm = 222; - manager->outputs[1].height_mm = 125; - manager->outputs[1].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; - manager->outputs[1].preferred_mode = &manager->modes[5]; - manager->outputs[1].n_modes = 4; - manager->outputs[1].modes = g_new0 (MetaMonitorMode *, 4); - manager->outputs[1].modes[0] = &manager->modes[0]; - manager->outputs[1].modes[1] = &manager->modes[1]; - manager->outputs[1].modes[2] = &manager->modes[2]; - manager->outputs[1].modes[3] = &manager->modes[5]; - manager->outputs[1].n_possible_crtcs = 3; - manager->outputs[1].possible_crtcs = g_new0 (MetaCRTC *, 3); - manager->outputs[1].possible_crtcs[0] = &manager->crtcs[0]; - manager->outputs[1].possible_crtcs[1] = &manager->crtcs[1]; - manager->outputs[1].possible_crtcs[2] = &manager->crtcs[2]; - manager->outputs[1].n_possible_clones = 0; - manager->outputs[1].possible_clones = g_new0 (MetaOutput *, 0); - manager->outputs[1].backlight = -1; - manager->outputs[1].backlight_min = 0; - manager->outputs[1].backlight_max = 0; - - manager->outputs[2].crtc = NULL; - manager->outputs[2].output_id = 8; - manager->outputs[2].name = g_strdup ("VGA"); - manager->outputs[2].vendor = g_strdup ("MetaProducts Inc."); - manager->outputs[2].product = g_strdup ("unknown"); - manager->outputs[2].serial = g_strdup ("0xC4FE"); - manager->outputs[2].width_mm = 309; - manager->outputs[2].height_mm = 174; - manager->outputs[2].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; - manager->outputs[2].preferred_mode = &manager->modes[0]; - manager->outputs[2].n_modes = 3; - manager->outputs[2].modes = g_new0 (MetaMonitorMode *, 3); - manager->outputs[2].modes[0] = &manager->modes[0]; - manager->outputs[2].modes[1] = &manager->modes[1]; - manager->outputs[2].modes[2] = &manager->modes[2]; - manager->outputs[2].n_possible_crtcs = 3; - manager->outputs[2].possible_crtcs = g_new0 (MetaCRTC *, 3); - manager->outputs[2].possible_crtcs[0] = &manager->crtcs[0]; - manager->outputs[2].possible_crtcs[1] = &manager->crtcs[1]; - manager->outputs[2].possible_crtcs[2] = &manager->crtcs[2]; - manager->outputs[2].n_possible_clones = 0; - manager->outputs[2].possible_clones = g_new0 (MetaOutput *, 0); - manager->outputs[2].backlight = -1; - manager->outputs[2].backlight_min = 0; - manager->outputs[2].backlight_max = 0; -} - -static void -apply_config_dummy (MetaMonitorManager *manager, - MetaCRTCInfo **crtcs, - unsigned int n_crtcs, - MetaOutputInfo **outputs, - unsigned int n_outputs) -{ - unsigned i; - int screen_width = 0, screen_height = 0; - - for (i = 0; i < n_crtcs; i++) - { - MetaCRTCInfo *crtc_info = crtcs[i]; - MetaCRTC *crtc = crtc_info->crtc; - crtc->is_dirty = TRUE; - - if (crtc_info->mode == NULL) - { - crtc->rect.x = 0; - crtc->rect.y = 0; - crtc->rect.width = 0; - crtc->rect.height = 0; - crtc->current_mode = NULL; - } - else - { - MetaMonitorMode *mode; - MetaOutput *output; - int i, n_outputs; - int width, height; - - mode = crtc_info->mode; - - if (meta_monitor_transform_is_rotated (crtc_info->transform)) - { - width = mode->height; - height = mode->width; - } - else - { - width = mode->width; - height = mode->height; - } - - crtc->rect.x = crtc_info->x; - crtc->rect.y = crtc_info->y; - crtc->rect.width = width; - crtc->rect.height = height; - crtc->current_mode = mode; - crtc->transform = crtc_info->transform; - - screen_width = MAX (screen_width, crtc_info->x + width); - screen_height = MAX (screen_height, crtc_info->y + height); - - n_outputs = crtc_info->outputs->len; - for (i = 0; i < n_outputs; i++) - { - output = ((MetaOutput**)crtc_info->outputs->pdata)[i]; - - output->is_dirty = TRUE; - output->crtc = crtc; - } - } - } - - for (i = 0; i < n_outputs; i++) - { - MetaOutputInfo *output_info = outputs[i]; - MetaOutput *output = output_info->output; - - output->is_primary = output_info->is_primary; - output->is_presentation = output_info->is_presentation; - } - - /* Disable CRTCs not mentioned in the list */ - for (i = 0; i < manager->n_crtcs; i++) - { - MetaCRTC *crtc = &manager->crtcs[i]; - - crtc->logical_monitor = NULL; - - if (crtc->is_dirty) - { - crtc->is_dirty = FALSE; - continue; - } - - crtc->rect.x = 0; - crtc->rect.y = 0; - crtc->rect.width = 0; - crtc->rect.height = 0; - crtc->current_mode = NULL; - } - - /* Disable outputs not mentioned in the list */ - for (i = 0; i < manager->n_outputs; i++) - { - MetaOutput *output = &manager->outputs[i]; - - if (output->is_dirty) - { - output->is_dirty = FALSE; - continue; - } - - output->crtc = NULL; - output->is_primary = FALSE; - } - - manager->screen_width = screen_width; - manager->screen_height = screen_height; - - meta_monitor_manager_rebuild_derived (manager); -} - -static GBytes * -read_edid_dummy (MetaMonitorManager *manager, - MetaOutput *output) -{ - return NULL; -} - -static char * -get_edid_file_dummy (MetaMonitorManager *manager, - MetaOutput *output) -{ - return NULL; -} - -static void meta_monitor_manager_init (MetaMonitorManager *manager) { } @@ -469,6 +168,40 @@ make_logical_config (MetaMonitorManager *manager) manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE); } +static GType +get_default_backend (void) +{ +#if defined(CLUTTER_WINDOWING_EGL) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + return META_TYPE_MONITOR_MANAGER_KMS; +#endif + +#if defined(CLUTTER_WINDOWING_X11) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11)) + { + /* If we're a Wayland compositor using the X11 backend, + * we're a nested configuration, so return the dummy + * monitor setup. */ + if (meta_is_wayland_compositor ()) + return META_TYPE_MONITOR_MANAGER_DUMMY; + else + return META_TYPE_MONITOR_MANAGER_XRANDR; + } +#endif + +#if defined(CLUTTER_WINDOWING_WAYLAND) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND)) + { + /* Use the dummy implementation on Wayland for now. + * In the future, we should support wl_fullscreen_output + * which will have CRTC management in the protocol. */ + return META_TYPE_MONITOR_MANAGER_DUMMY; + } +#endif + + g_assert_not_reached (); +} + static MetaMonitorManager * meta_monitor_manager_new (void) { @@ -478,7 +211,7 @@ meta_monitor_manager_new (void) env = g_getenv ("META_DEBUG_MULTIMONITOR"); if (env == NULL) - type = META_TYPE_MONITOR_MANAGER_XRANDR; + type = get_default_backend (); else if (strcmp (env, "xrandr") == 0) type = META_TYPE_MONITOR_MANAGER_XRANDR; else @@ -513,17 +246,18 @@ meta_monitor_manager_constructed (GObject *object) MetaOutput *old_outputs; MetaCRTC *old_crtcs; MetaMonitorMode *old_modes; - int n_old_outputs; + unsigned int n_old_outputs, n_old_modes; old_outputs = manager->outputs; n_old_outputs = manager->n_outputs; old_modes = manager->modes; + n_old_modes = manager->n_modes; old_crtcs = manager->crtcs; read_current_config (manager); meta_monitor_manager_free_output_array (old_outputs, n_old_outputs); - g_free (old_modes); + meta_monitor_manager_free_mode_array (old_modes, n_old_modes); g_free (old_crtcs); } @@ -565,19 +299,39 @@ meta_monitor_manager_free_output_array (MetaOutput *old_outputs, g_free (old_outputs[i].modes); g_free (old_outputs[i].possible_crtcs); g_free (old_outputs[i].possible_clones); + + if (old_outputs[i].driver_notify) + old_outputs[i].driver_notify (&old_outputs[i]); } g_free (old_outputs); } +void +meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes, + int n_old_modes) +{ + int i; + + for (i = 0; i < n_old_modes; i++) + { + g_free (old_modes[i].name); + + if (old_modes[i].driver_notify) + old_modes[i].driver_notify (&old_modes[i]); + } + + g_free (old_modes); +} + static void meta_monitor_manager_finalize (GObject *object) { MetaMonitorManager *manager = META_MONITOR_MANAGER (object); meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs); + meta_monitor_manager_free_mode_array (manager->modes, manager->n_modes); g_free (manager->monitor_infos); - g_free (manager->modes); g_free (manager->crtcs); G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object); @@ -635,6 +389,20 @@ meta_monitor_manager_get_property (GObject *object, } } +static GBytes * +meta_monitor_manager_real_read_edid (MetaMonitorManager *manager, + MetaOutput *output) +{ + return NULL; +} + +static char * +meta_monitor_manager_real_get_edid_file (MetaMonitorManager *manager, + MetaOutput *output) +{ + return NULL; +} + static void meta_monitor_manager_class_init (MetaMonitorManagerClass *klass) { @@ -646,10 +414,8 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass) object_class->dispose = meta_monitor_manager_dispose; object_class->finalize = meta_monitor_manager_finalize; - klass->read_current = read_current_dummy; - klass->apply_configuration = apply_config_dummy; - klass->get_edid_file = get_edid_file_dummy; - klass->read_edid = read_edid_dummy; + klass->get_edid_file = meta_monitor_manager_real_get_edid_file; + klass->read_edid = meta_monitor_manager_real_read_edid; signals[CONFIRM_DISPLAY_CHANGE] = g_signal_new ("confirm-display-change", @@ -1453,12 +1219,21 @@ meta_monitor_manager_get_resources (MetaMonitorManager *manager, MetaOutput **outputs, unsigned int *n_outputs) { - *modes = manager->modes; - *n_modes = manager->n_modes; - *crtcs = manager->crtcs; - *n_crtcs = manager->n_crtcs; - *outputs = manager->outputs; - *n_outputs = manager->n_outputs; + if (modes) + { + *modes = manager->modes; + *n_modes = manager->n_modes; + } + if (crtcs) + { + *crtcs = manager->crtcs; + *n_crtcs = manager->n_crtcs; + } + if (outputs) + { + *outputs = manager->outputs; + *n_outputs = manager->n_outputs; + } } int diff --git a/src/core/monitor-private.h b/src/backends/meta-monitor-manager.h index 48cad40..0feb73d 100644 --- a/src/core/monitor-private.h +++ b/src/backends/meta-monitor-manager.h @@ -42,31 +42,16 @@ #include <meta/screen.h> #include "stack-tracker.h" #include "ui.h" -#ifdef HAVE_WAYLAND #include <wayland-server.h> -#endif -#include "meta-xrandr-shared.h" -#include "meta-dbus-xrandr.h" +#include "meta-display-config-shared.h" +#include "meta-dbus-display-config.h" typedef struct _MetaMonitorManagerClass MetaMonitorManagerClass; typedef struct _MetaMonitorManager MetaMonitorManager; typedef struct _MetaMonitorConfigClass MetaMonitorConfigClass; typedef struct _MetaMonitorConfig MetaMonitorConfig; -#ifndef HAVE_WAYLAND -enum wl_output_transform { - WL_OUTPUT_TRANSFORM_NORMAL, - WL_OUTPUT_TRANSFORM_90, - WL_OUTPUT_TRANSFORM_180, - WL_OUTPUT_TRANSFORM_270, - WL_OUTPUT_TRANSFORM_FLIPPED, - WL_OUTPUT_TRANSFORM_FLIPPED_90, - WL_OUTPUT_TRANSFORM_FLIPPED_180, - WL_OUTPUT_TRANSFORM_FLIPPED_270 -}; -#endif - typedef struct _MetaOutput MetaOutput; typedef struct _MetaCRTC MetaCRTC; typedef struct _MetaMonitorMode MetaMonitorMode; @@ -115,6 +100,9 @@ struct _MetaOutput gboolean is_primary; gboolean is_presentation; + gpointer driver_private; + GDestroyNotify driver_notify; + /* get a new preferred mode on hotplug events, to handle dynamic guest resizing */ gboolean hotplug_mode_update; }; @@ -134,16 +122,23 @@ struct _MetaCRTC /* Used when changing configuration */ gboolean is_dirty; + + /* Updated by MetaCursorTracker */ + gboolean has_hw_cursor; }; struct _MetaMonitorMode { /* The low-level ID of this mode, used to apply back configuration */ glong mode_id; + char *name; int width; int height; float refresh_rate; + + gpointer driver_private; + GDestroyNotify driver_notify; }; /** @@ -232,8 +227,6 @@ struct _MetaMonitorManager CRTCs refer to stuff that can drive outputs (like encoders, but less tied to the HW), while monitor_infos refer to logical ones. - - See also the comment in monitor-private.h */ MetaOutput *outputs; unsigned int n_outputs; @@ -340,50 +333,13 @@ void meta_monitor_manager_apply_configuration (MetaMonitorManager void meta_monitor_manager_confirm_configuration (MetaMonitorManager *manager, gboolean ok); -#define META_TYPE_MONITOR_MANAGER_XRANDR (meta_monitor_manager_xrandr_get_type ()) -#define META_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandr)) -#define META_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass)) -#define META_IS_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_XRANDR)) -#define META_IS_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_XRANDR)) -#define META_MONITOR_MANAGER_XRANDR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass)) - -typedef struct _MetaMonitorManagerXrandrClass MetaMonitorManagerXrandrClass; -typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr; - -GType meta_monitor_manager_xrandr_get_type (void); - -#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ()) -#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig)) -#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass)) -#define META_IS_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG)) -#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_CONFIG)) -#define META_MONITOR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass)) - -GType meta_monitor_config_get_type (void) G_GNUC_CONST; - -MetaMonitorConfig *meta_monitor_config_new (void); - -gboolean meta_monitor_config_match_current (MetaMonitorConfig *config, - MetaMonitorManager *manager); - -gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config, - MetaMonitorManager *manager); - -void meta_monitor_config_make_default (MetaMonitorConfig *config, - MetaMonitorManager *manager); - -void meta_monitor_config_update_current (MetaMonitorConfig *config, - MetaMonitorManager *manager); -void meta_monitor_config_make_persistent (MetaMonitorConfig *config); - -void meta_monitor_config_restore_previous (MetaMonitorConfig *config, - MetaMonitorManager *manager); - void meta_crtc_info_free (MetaCRTCInfo *info); void meta_output_info_free (MetaOutputInfo *info); void meta_monitor_manager_free_output_array (MetaOutput *old_outputs, int n_old_outputs); +void meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes, + int n_old_modes); gboolean meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager); /* Returns true if transform causes width and height to be inverted diff --git a/src/backends/native/meta-idle-monitor-native.c b/src/backends/native/meta-idle-monitor-native.c new file mode 100644 index 0000000..13d8d51 --- /dev/null +++ b/src/backends/native/meta-idle-monitor-native.c @@ -0,0 +1,219 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#include "config.h" + +#include "meta-idle-monitor-native.h" +#include "meta-idle-monitor-private.h" + +#include <meta/util.h> +#include "display-private.h" + +#include <string.h> + +struct _MetaIdleMonitorNative +{ + MetaIdleMonitor parent; + + guint64 last_event_time; +}; + +struct _MetaIdleMonitorNativeClass +{ + MetaIdleMonitorClass parent_class; +}; + +typedef struct { + MetaIdleMonitorWatch base; + + GSource *timeout_source; +} MetaIdleMonitorWatchNative; + +G_DEFINE_TYPE (MetaIdleMonitorNative, meta_idle_monitor_native, META_TYPE_IDLE_MONITOR) + +static gint64 +meta_idle_monitor_native_get_idletime (MetaIdleMonitor *monitor) +{ + MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor); + + return (g_get_monotonic_time () - monitor_native->last_event_time) / 1000; +} + +static guint32 +get_next_watch_serial (void) +{ + static guint32 serial = 0; + g_atomic_int_inc (&serial); + return serial; +} + +static gboolean +native_dispatch_timeout (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + MetaIdleMonitorWatchNative *watch_native = user_data; + MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native; + + _meta_idle_monitor_watch_fire (watch); + g_source_set_ready_time (watch_native->timeout_source, -1); + return TRUE; +} + +static GSourceFuncs native_source_funcs = { + NULL, /* prepare */ + NULL, /* check */ + native_dispatch_timeout, + NULL, /* finalize */ +}; + +static void +free_watch (gpointer data) +{ + MetaIdleMonitorWatchNative *watch_native = data; + MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native; + MetaIdleMonitor *monitor = watch->monitor; + + g_object_ref (monitor); + + if (watch->idle_source_id) + { + g_source_remove (watch->idle_source_id); + watch->idle_source_id = 0; + } + + if (watch->notify != NULL) + watch->notify (watch->user_data); + + if (watch_native->timeout_source != NULL) + g_source_destroy (watch_native->timeout_source); + + g_object_unref (monitor); + g_slice_free (MetaIdleMonitorWatchNative, watch_native); +} + +static MetaIdleMonitorWatch * +meta_idle_monitor_native_make_watch (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatchNative *watch_native; + MetaIdleMonitorWatch *watch; + MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor); + + watch_native = g_slice_new0 (MetaIdleMonitorWatchNative); + watch = (MetaIdleMonitorWatch *) watch_native; + + watch->monitor = monitor; + watch->id = get_next_watch_serial (); + watch->callback = callback; + watch->user_data = user_data; + watch->notify = notify; + watch->timeout_msec = timeout_msec; + + if (timeout_msec != 0) + { + GSource *source = g_source_new (&native_source_funcs, sizeof (GSource)); + + g_source_set_callback (source, NULL, watch, NULL); + g_source_set_ready_time (source, monitor_native->last_event_time + timeout_msec * 1000); + g_source_attach (source, NULL); + g_source_unref (source); + + watch_native->timeout_source = source; + } + + return watch; +} + +static void +meta_idle_monitor_native_class_init (MetaIdleMonitorNativeClass *klass) +{ + MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass); + + idle_monitor_class->get_idletime = meta_idle_monitor_native_get_idletime; + idle_monitor_class->make_watch = meta_idle_monitor_native_make_watch; +} + +static void +meta_idle_monitor_native_init (MetaIdleMonitorNative *monitor_native) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_native); + + monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch); +} + +typedef struct { + MetaIdleMonitorNative *monitor_native; + GList *fired_watches; +} CheckNativeClosure; + +static gboolean +check_native_watch (gpointer key, + gpointer value, + gpointer user_data) +{ + MetaIdleMonitorWatchNative *watch_native = value; + MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native; + CheckNativeClosure *closure = user_data; + gboolean steal; + + if (watch->timeout_msec == 0) + { + closure->fired_watches = g_list_prepend (closure->fired_watches, watch); + steal = TRUE; + } + else + { + g_source_set_ready_time (watch_native->timeout_source, + closure->monitor_native->last_event_time + + watch->timeout_msec * 1000); + steal = FALSE; + } + + return steal; +} + +static void +fire_native_watch (gpointer watch, + gpointer data) +{ + _meta_idle_monitor_watch_fire (watch); +} + +void +meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor) +{ + MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor); + CheckNativeClosure closure; + + monitor_native->last_event_time = g_get_monotonic_time (); + + closure.monitor_native = monitor_native; + closure.fired_watches = NULL; + g_hash_table_foreach_steal (monitor->watches, check_native_watch, &closure); + + g_list_foreach (closure.fired_watches, fire_native_watch, NULL); + g_list_free (closure.fired_watches); +} diff --git a/src/backends/native/meta-idle-monitor-native.h b/src/backends/native/meta-idle-monitor-native.h new file mode 100644 index 0000000..37745c4 --- /dev/null +++ b/src/backends/native/meta-idle-monitor-native.h @@ -0,0 +1,43 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#ifndef META_IDLE_MONITOR_NATIVE_H +#define META_IDLE_MONITOR_NATIVE_H + +#include <glib-object.h> +#include <meta/meta-idle-monitor.h> + +#define META_TYPE_IDLE_MONITOR_NATIVE (meta_idle_monitor_native_get_type ()) +#define META_IDLE_MONITOR_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNative)) +#define META_IDLE_MONITOR_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNativeClass)) +#define META_IS_IDLE_MONITOR_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR_NATIVE)) +#define META_IS_IDLE_MONITOR_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_IDLE_MONITOR_NATIVE)) +#define META_IDLE_MONITOR_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNativeClass)) + +typedef struct _MetaIdleMonitorNative MetaIdleMonitorNative; +typedef struct _MetaIdleMonitorNativeClass MetaIdleMonitorNativeClass; + +GType meta_idle_monitor_native_get_type (void); + +void meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor); + +#endif /* META_IDLE_MONITOR_NATIVE_H */ diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c new file mode 100644 index 0000000..698c606 --- /dev/null +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -0,0 +1,939 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Author: Giovanni Campagna <gcampagn@redhat.com> + */ + +#include "config.h" + +#include "meta-monitor-manager-kms.h" + +#include <string.h> +#include <stdlib.h> +#include <clutter/clutter.h> + +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <unistd.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include <meta/main.h> +#include <meta/errors.h> +#include "edid.h" + +#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1) + +typedef struct { + drmModeConnector *connector; + + unsigned n_encoders; + drmModeEncoderPtr *encoders; + drmModeEncoderPtr current_encoder; + + /* bitmasks of encoder position in the resources array */ + uint32_t encoder_mask; + uint32_t enc_clone_mask; + + uint32_t dpms_prop_id; + uint32_t edid_blob_id; +} MetaOutputKms; + +struct _MetaMonitorManagerKms +{ + MetaMonitorManager parent_instance; + + int fd; + + drmModeConnector **connectors; + unsigned int n_connectors; + + drmModeEncoder **encoders; + unsigned int n_encoders; + + drmModeEncoder *current_encoder; +}; + +struct _MetaMonitorManagerKmsClass +{ + MetaMonitorManagerClass parent_class; +}; + +G_DEFINE_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, META_TYPE_MONITOR_MANAGER); + +static void +free_resources (MetaMonitorManagerKms *manager_kms) +{ + unsigned i; + + for (i = 0; i < manager_kms->n_encoders; i++) + drmModeFreeEncoder (manager_kms->encoders[i]); + for (i = 0; i < manager_kms->n_connectors; i++) + drmModeFreeConnector (manager_kms->connectors[i]); + + g_free (manager_kms->encoders); + g_free (manager_kms->connectors); +} + +static int +compare_outputs (const void *one, + const void *two) +{ + const MetaOutput *o_one = one, *o_two = two; + + return strcmp (o_one->name, o_two->name); +} + +static char * +make_output_name (drmModeConnector *connector) +{ + static const char * const connector_type_names[] = { + "unknown", "VGA", "DVII", "DVID", "DVID", "Composite", + "SVIDEO", "LVDS", "Component", "9PinDIN", "DisplayPort", + "HDMIA", "HDMIB", "TV", "eDP" + }; + const char *connector_type_name; + + if (connector->connector_type < G_N_ELEMENTS (connector_type_names)) + connector_type_name = connector_type_names[connector->connector_type]; + else + connector_type_name = "unknown"; + + return g_strdup_printf ("%s%d", connector_type_name, connector->connector_id); +} + +static void +meta_output_destroy_notify (MetaOutput *output) +{ + MetaOutputKms *output_kms; + unsigned i; + + output_kms = output->driver_private; + + for (i = 0; i < output_kms->n_encoders; i++) + drmModeFreeEncoder (output_kms->encoders[i]); + g_free (output_kms->encoders); + + g_slice_free (MetaOutputKms, output_kms); +} + +static void +meta_monitor_mode_destroy_notify (MetaMonitorMode *output) +{ + g_slice_free (drmModeModeInfo, output->driver_private); +} + +static gboolean +drm_mode_equal (gconstpointer one, + gconstpointer two) +{ + const drmModeModeInfo *m_one = one; + const drmModeModeInfo *m_two = two; + + return m_one->clock == m_two->clock && + m_one->hdisplay == m_two->hdisplay && + m_one->hsync_start == m_two->hsync_start && + m_one->hsync_end == m_two->hsync_end && + m_one->htotal == m_two->htotal && + m_one->hskew == m_two->hskew && + m_one->vdisplay == m_two->vdisplay && + m_one->vsync_start == m_two->vsync_start && + m_one->vsync_end == m_two->vsync_end && + m_one->vtotal == m_two->vtotal && + m_one->vscan == m_two->vscan && + m_one->vrefresh == m_two->vrefresh && + m_one->flags == m_two->flags && + m_one->type == m_two->type && + strncmp (m_one->name, m_two->name, DRM_DISPLAY_MODE_LEN) == 0; +} + +static guint +drm_mode_hash (gconstpointer ptr) +{ + const drmModeModeInfo *mode = ptr; + guint hash = 0; + + /* We don't include the name in the hash because it's generally + derived from the other fields (hdisplay, vdisplay and flags) + */ + + hash ^= mode->clock; + hash ^= mode->hdisplay ^ mode->hsync_start ^ mode->hsync_end; + hash ^= mode->vdisplay ^ mode->vsync_start ^ mode->vsync_end; + hash ^= mode->vrefresh; + hash ^= mode->flags ^ mode->type; + + return hash; +} + +static void +find_properties (MetaMonitorManagerKms *manager_kms, + MetaOutputKms *output_kms) +{ + drmModePropertyPtr prop; + int i; + + for (i = 0; i < output_kms->connector->count_props; i++) + { + prop = drmModeGetProperty (manager_kms->fd, output_kms->connector->props[i]); + if (!prop) + continue; + + if ((prop->flags & DRM_MODE_PROP_ENUM) && + strcmp(prop->name, "DPMS") == 0) + output_kms->dpms_prop_id = prop->prop_id; + else if ((prop->flags & DRM_MODE_PROP_BLOB) && + strcmp (prop->name, "EDID") == 0) + output_kms->edid_blob_id = output_kms->connector->prop_values[i]; + + drmModeFreeProperty(prop); + } +} + +static GBytes * +read_output_edid (MetaMonitorManagerKms *manager_kms, + MetaOutput *output) +{ + MetaOutputKms *output_kms = output->driver_private; + drmModePropertyBlobPtr edid_blob = NULL; + + if (output_kms->edid_blob_id == 0) + return NULL; + + edid_blob = drmModeGetPropertyBlob (manager_kms->fd, output_kms->edid_blob_id); + if (!edid_blob) + { + meta_warning ("Failed to read EDID of output %s: %s\n", output->name, strerror(errno)); + return NULL; + } + + if (edid_blob->length > 0) + return g_bytes_new_with_free_func (edid_blob->data, edid_blob->length, + (GDestroyNotify)drmModeFreePropertyBlob, edid_blob); + else + { + drmModeFreePropertyBlob (edid_blob); + return NULL; + } +} + +static MetaMonitorMode * +find_meta_mode (MetaMonitorManager *manager, + const drmModeModeInfo *drm_mode) +{ + unsigned k; + + for (k = 0; k < manager->n_modes; k++) + { + if (drm_mode_equal (drm_mode, manager->modes[k].driver_private)) + return &manager->modes[k]; + } + + g_assert_not_reached (); + return NULL; +} + +static MetaOutput * +find_output_by_id (MetaOutput *outputs, + unsigned n_outputs, + glong id) +{ + unsigned i; + + for (i = 0; i < n_outputs; i++) + if (outputs[i].output_id == id) + return &outputs[i]; + + return NULL; +} + +static void +meta_monitor_manager_kms_read_current (MetaMonitorManager *manager) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + drmModeRes *resources; + GHashTable *modes; + GHashTableIter iter; + drmModeModeInfo *mode; + unsigned int i, j, k; + unsigned int n_actual_outputs; + int width, height; + MetaOutput *old_outputs; + unsigned int n_old_outputs; + + resources = drmModeGetResources(manager_kms->fd); + modes = g_hash_table_new (drm_mode_hash, drm_mode_equal); + + manager->max_screen_width = resources->max_width; + manager->max_screen_height = resources->max_height; + + manager->power_save_mode = META_POWER_SAVE_ON; + + old_outputs = manager->outputs; + n_old_outputs = manager->n_outputs; + + /* Note: we must not free the public structures (output, crtc, monitor + mode and monitor info) here, they must be kept alive until the API + users are done with them after we emit monitors-changed, and thus + are freed by the platform-independent layer. */ + free_resources (manager_kms); + + manager_kms->n_connectors = resources->count_connectors; + manager_kms->connectors = g_new (drmModeConnector *, manager_kms->n_connectors); + for (i = 0; i < manager_kms->n_connectors; i++) + { + drmModeConnector *connector; + + connector = drmModeGetConnector (manager_kms->fd, resources->connectors[i]); + manager_kms->connectors[i] = connector; + + if (connector->connection == DRM_MODE_CONNECTED) + { + /* Collect all modes for this connector */ + for (j = 0; j < (unsigned)connector->count_modes; j++) + g_hash_table_add (modes, &connector->modes[j]); + } + } + + manager_kms->n_encoders = resources->count_encoders; + manager_kms->encoders = g_new (drmModeEncoder *, manager_kms->n_encoders); + for (i = 0; i < manager_kms->n_encoders; i++) + { + manager_kms->encoders[i] = drmModeGetEncoder (manager_kms->fd, + resources->encoders[i]); + } + + manager->n_modes = g_hash_table_size (modes); + manager->modes = g_new0 (MetaMonitorMode, manager->n_modes); + g_hash_table_iter_init (&iter, modes); + i = 0; + while (g_hash_table_iter_next (&iter, NULL, (gpointer)&mode)) + { + MetaMonitorMode *meta_mode; + + meta_mode = &manager->modes[i]; + + meta_mode->mode_id = i; + meta_mode->name = g_strndup (mode->name, DRM_DISPLAY_MODE_LEN); + meta_mode->width = mode->hdisplay; + meta_mode->height = mode->vdisplay; + meta_mode->refresh_rate = (1000 * mode->clock / + ((float)mode->htotal * mode->vtotal)); + + meta_mode->driver_private = g_slice_dup (drmModeModeInfo, mode); + meta_mode->driver_notify = (GDestroyNotify)meta_monitor_mode_destroy_notify; + + i++; + } + g_hash_table_destroy (modes); + + manager->n_crtcs = resources->count_crtcs; + manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs); + width = 0; height = 0; + for (i = 0; i < (unsigned)resources->count_crtcs; i++) + { + drmModeCrtc *crtc; + MetaCRTC *meta_crtc; + + crtc = drmModeGetCrtc (manager_kms->fd, resources->crtcs[i]); + + meta_crtc = &manager->crtcs[i]; + + meta_crtc->crtc_id = crtc->crtc_id; + meta_crtc->rect.x = crtc->x; + meta_crtc->rect.y = crtc->y; + meta_crtc->rect.width = crtc->width; + meta_crtc->rect.height = crtc->height; + meta_crtc->is_dirty = FALSE; + meta_crtc->transform = WL_OUTPUT_TRANSFORM_NORMAL; + /* FIXME: implement! */ + meta_crtc->all_transforms = 1 << WL_OUTPUT_TRANSFORM_NORMAL; + + if (crtc->mode_valid) + { + for (j = 0; j < manager->n_modes; j++) + { + if (drm_mode_equal (&crtc->mode, manager->modes[j].driver_private)) + { + meta_crtc->current_mode = &manager->modes[j]; + break; + } + } + + width = MAX (width, meta_crtc->rect.x + meta_crtc->rect.width); + height = MAX (height, meta_crtc->rect.y + meta_crtc->rect.height); + } + + drmModeFreeCrtc (crtc); + } + + manager->screen_width = width; + manager->screen_height = height; + + manager->outputs = g_new0 (MetaOutput, manager_kms->n_connectors); + n_actual_outputs = 0; + + for (i = 0; i < manager_kms->n_connectors; i++) + { + MetaOutput *meta_output, *old_output; + MetaOutputKms *output_kms; + drmModeConnector *connector; + GArray *crtcs; + unsigned int crtc_mask; + GBytes *edid; + + connector = manager_kms->connectors[i]; + meta_output = &manager->outputs[n_actual_outputs]; + + if (connector->connection == DRM_MODE_CONNECTED) + { + meta_output->driver_private = output_kms = g_slice_new0 (MetaOutputKms); + meta_output->driver_notify = (GDestroyNotify)meta_output_destroy_notify; + + meta_output->output_id = connector->connector_id; + meta_output->name = make_output_name (connector); + meta_output->width_mm = connector->mmWidth; + meta_output->height_mm = connector->mmHeight; + + switch (connector->subpixel) + { + case DRM_MODE_SUBPIXEL_NONE: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE; + break; + case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB; + break; + case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR; + break; + case DRM_MODE_SUBPIXEL_VERTICAL_RGB: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB; + break; + case DRM_MODE_SUBPIXEL_VERTICAL_BGR: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR; + break; + case DRM_MODE_SUBPIXEL_UNKNOWN: + default: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; + break; + } + + meta_output->n_modes = connector->count_modes; + meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes); + for (j = 0; j < meta_output->n_modes; j++) + meta_output->modes[j] = find_meta_mode (manager, &connector->modes[j]); + meta_output->preferred_mode = meta_output->modes[0]; + + output_kms->connector = connector; + output_kms->n_encoders = connector->count_encoders; + output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders); + + crtc_mask = ~(unsigned int)0; + for (j = 0; j < output_kms->n_encoders; j++) + { + output_kms->encoders[j] = drmModeGetEncoder (manager_kms->fd, connector->encoders[j]); + + /* We only list CRTCs as supported if they are supported by all encoders + for this connectors. + + This is what xf86-video-modesetting does (see drmmode_output_init()) + */ + crtc_mask &= output_kms->encoders[j]->possible_crtcs; + + if (output_kms->encoders[j]->encoder_id == connector->encoder_id) + output_kms->current_encoder = output_kms->encoders[j]; + } + + crtcs = g_array_new (FALSE, FALSE, sizeof (MetaCRTC*)); + + for (j = 0; j < manager->n_crtcs; j++) + { + if (crtc_mask & (1 << j)) + { + MetaCRTC *crtc = &manager->crtcs[j]; + g_array_append_val (crtcs, crtc); + } + } + + meta_output->n_possible_crtcs = crtcs->len; + meta_output->possible_crtcs = (void*)g_array_free (crtcs, FALSE); + + if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0) + { + for (j = 0; j < manager->n_crtcs; j++) + { + if (manager->crtcs[j].crtc_id == output_kms->current_encoder->crtc_id) + { + meta_output->crtc = &manager->crtcs[j]; + break; + } + } + } + else + meta_output->crtc = NULL; + + old_output = find_output_by_id (old_outputs, n_old_outputs, + meta_output->output_id); + if (old_output) + { + meta_output->is_primary = old_output->is_primary; + meta_output->is_presentation = old_output->is_presentation; + } + else + { + meta_output->is_primary = FALSE; + meta_output->is_presentation = FALSE; + } + + find_properties (manager_kms, output_kms); + + edid = read_output_edid (manager_kms, meta_output); + if (edid) + { + MonitorInfo *parsed_edid; + gsize len; + + parsed_edid = decode_edid (g_bytes_get_data (edid, &len)); + if (parsed_edid) + { + meta_output->vendor = g_strndup (parsed_edid->manufacturer_code, 4); + meta_output->product = g_strndup (parsed_edid->dsc_product_name, 14); + meta_output->serial = g_strndup (parsed_edid->dsc_serial_number, 14); + + g_free (parsed_edid); + } + + g_bytes_unref (edid); + } + if (!meta_output->vendor) + { + meta_output->vendor = g_strdup ("unknown"); + meta_output->product = g_strdup ("unknown"); + meta_output->serial = g_strdup ("unknown"); + } + + /* FIXME: backlight is a very driver specific thing unfortunately, + every DDX does its own thing, and the dumb KMS API does not include it. + + For example, xf86-video-intel has a list of paths to probe in /sys/class/backlight + (one for each major HW maker, and then some). + We can't do the same because we're not root. + It might be best to leave backlight out of the story and rely on the setuid + helper in gnome-settings-daemon. + */ + meta_output->backlight_min = 0; + meta_output->backlight_max = 0; + meta_output->backlight = -1; + + n_actual_outputs++; + } + } + + manager->n_outputs = n_actual_outputs; + manager->outputs = g_renew (MetaOutput, manager->outputs, manager->n_outputs); + + /* Sort the outputs for easier handling in MetaMonitorConfig */ + qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs); + + /* Now fix the clones. + Code mostly inspired by xf86-video-modesetting. */ + + /* XXX: intel hardware doesn't usually have clones, but I only have laptops with + intel cards, so this code was never tested! */ + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *meta_output; + MetaOutputKms *output_kms; + + meta_output = &manager->outputs[i]; + output_kms = meta_output->driver_private; + + output_kms->enc_clone_mask = 0xff; + output_kms->encoder_mask = 0; + + for (j = 0; j < output_kms->n_encoders; j++) + { + for (k = 0; k < manager_kms->n_encoders; k++) + { + if (output_kms->encoders[j]->encoder_id == manager_kms->encoders[k]->encoder_id) + { + output_kms->encoder_mask |= (1 << k); + break; + } + } + + output_kms->enc_clone_mask &= output_kms->encoders[j]->possible_clones; + } + } + + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *meta_output; + MetaOutputKms *output_kms; + + meta_output = &manager->outputs[i]; + output_kms = meta_output->driver_private; + + if (output_kms->enc_clone_mask == 0) + continue; + + for (j = 0; j < manager->n_outputs; j++) + { + MetaOutput *meta_clone; + MetaOutputKms *clone_kms; + + meta_clone = &manager->outputs[i]; + clone_kms = meta_clone->driver_private; + + if (meta_clone == meta_output) + continue; + + if (clone_kms->encoder_mask == 0) + continue; + + if (clone_kms->encoder_mask == output_kms->enc_clone_mask) + { + meta_output->n_possible_clones++; + meta_output->possible_clones = g_renew (MetaOutput *, + meta_output->possible_clones, + meta_output->n_possible_clones); + meta_output->possible_clones[meta_output->n_possible_clones - 1] = meta_clone; + } + } + } + + drmModeFreeResources (resources); +} + +static GBytes * +meta_monitor_manager_kms_read_edid (MetaMonitorManager *manager, + MetaOutput *output) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + + return read_output_edid (manager_kms, output); +} + +static void +meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, + MetaPowerSave mode) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + uint64_t state; + unsigned i; + + switch (mode) { + case META_POWER_SAVE_ON: + state = DRM_MODE_DPMS_ON; + break; + case META_POWER_SAVE_STANDBY: + state = DRM_MODE_DPMS_STANDBY; + break; + case META_POWER_SAVE_SUSPEND: + state = DRM_MODE_DPMS_SUSPEND; + break; + case META_POWER_SAVE_OFF: + state = DRM_MODE_DPMS_OFF; + break; + default: + return; + } + + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *meta_output; + MetaOutputKms *output_kms; + + meta_output = &manager->outputs[i]; + output_kms = meta_output->driver_private; + + if (output_kms->dpms_prop_id != 0) + { + int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->output_id, + output_kms->dpms_prop_id, state); + + if (ok < 0) + meta_warning ("Failed to set power save mode for output %s: %s\n", + meta_output->name, strerror (errno)); + } + } +} + +static void +crtc_free (CoglKmsCrtc *crtc) +{ + g_free (crtc->connectors); + g_slice_free (CoglKmsCrtc, crtc); +} + +static void +meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, + MetaCRTCInfo **crtcs, + unsigned int n_crtcs, + MetaOutputInfo **outputs, + unsigned int n_outputs) +{ + ClutterBackend *backend; + CoglContext *cogl_context; + CoglDisplay *cogl_display; + unsigned i; + GPtrArray *cogl_crtcs; + int screen_width, screen_height; + gboolean ok; + GError *error; + + cogl_crtcs = g_ptr_array_new_full (manager->n_crtcs, (GDestroyNotify)crtc_free); + screen_width = 0; screen_height = 0; + for (i = 0; i < n_crtcs; i++) + { + MetaCRTCInfo *crtc_info = crtcs[i]; + MetaCRTC *crtc = crtc_info->crtc; + CoglKmsCrtc *cogl_crtc; + + crtc->is_dirty = TRUE; + + cogl_crtc = g_slice_new0 (CoglKmsCrtc); + g_ptr_array_add (cogl_crtcs, cogl_crtc); + + if (crtc_info->mode == NULL) + { + cogl_crtc->id = crtc->crtc_id; + cogl_crtc->x = 0; + cogl_crtc->y = 0; + cogl_crtc->count = 0; + memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo)); + cogl_crtc->connectors = NULL; + cogl_crtc->count = 0; + + crtc->rect.x = 0; + crtc->rect.y = 0; + crtc->rect.width = 0; + crtc->rect.height = 0; + crtc->current_mode = NULL; + } + else + { + MetaMonitorMode *mode; + uint32_t *connectors; + unsigned int j, n_connectors; + int width, height; + + mode = crtc_info->mode; + + cogl_crtc->id = crtc->crtc_id; + cogl_crtc->x = crtc_info->x; + cogl_crtc->y = crtc_info->y; + cogl_crtc->count = n_connectors = crtc_info->outputs->len; + cogl_crtc->connectors = connectors = g_new (uint32_t, n_connectors); + + for (j = 0; j < n_connectors; j++) + { + MetaOutput *output = g_ptr_array_index (crtc_info->outputs, j); + + connectors[j] = output->output_id; + + output->is_dirty = TRUE; + output->crtc = crtc; + } + + memcpy (&cogl_crtc->mode, crtc_info->mode->driver_private, + sizeof (drmModeModeInfo)); + + if (meta_monitor_transform_is_rotated (crtc_info->transform)) + { + width = mode->height; + height = mode->width; + } + else + { + width = mode->width; + height = mode->height; + } + + screen_width = MAX (screen_width, crtc_info->x + width); + screen_height = MAX (screen_height, crtc_info->y + height); + + crtc->rect.x = crtc_info->x; + crtc->rect.y = crtc_info->y; + crtc->rect.width = width; + crtc->rect.height = height; + crtc->current_mode = mode; + crtc->transform = crtc_info->transform; + } + } + + /* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE, + because they weren't seen in the first loop) */ + for (i = 0; i < manager->n_crtcs; i++) + { + MetaCRTC *crtc = &manager->crtcs[i]; + CoglKmsCrtc *cogl_crtc; + + crtc->logical_monitor = NULL; + + if (crtc->is_dirty) + { + crtc->is_dirty = FALSE; + continue; + } + + cogl_crtc = g_slice_new0 (CoglKmsCrtc); + g_ptr_array_add (cogl_crtcs, cogl_crtc); + + cogl_crtc->id = crtc->crtc_id; + cogl_crtc->x = 0; + cogl_crtc->y = 0; + cogl_crtc->count = 0; + memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo)); + cogl_crtc->connectors = NULL; + cogl_crtc->count = 0; + + crtc->rect.x = 0; + crtc->rect.y = 0; + crtc->rect.width = 0; + crtc->rect.height = 0; + crtc->current_mode = NULL; + } + + backend = clutter_get_default_backend (); + cogl_context = clutter_backend_get_cogl_context (backend); + cogl_display = cogl_context_get_display (cogl_context); + + error = NULL; + ok = cogl_kms_display_set_layout (cogl_display, screen_width, screen_height, + (CoglKmsCrtc**)cogl_crtcs->pdata, cogl_crtcs->len, &error); + g_ptr_array_unref (cogl_crtcs); + + if (!ok) + { + meta_warning ("Applying display configuration failed: %s\n", error->message); + g_error_free (error); + return; + } + + for (i = 0; i < n_outputs; i++) + { + MetaOutputInfo *output_info = outputs[i]; + MetaOutput *output = output_info->output; + + output->is_primary = output_info->is_primary; + output->is_presentation = output_info->is_presentation; + } + + /* Disable outputs not mentioned in the list */ + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *output = &manager->outputs[i]; + + if (output->is_dirty) + { + output->is_dirty = FALSE; + continue; + } + + output->crtc = NULL; + output->is_primary = FALSE; + } + + manager->screen_width = screen_width; + manager->screen_height = screen_height; + + meta_monitor_manager_rebuild_derived (manager); +} + +static void +meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager *manager, + MetaCRTC *crtc, + gsize *size, + unsigned short **red, + unsigned short **green, + unsigned short **blue) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + drmModeCrtc *kms_crtc; + + kms_crtc = drmModeGetCrtc (manager_kms->fd, crtc->crtc_id); + + *size = kms_crtc->gamma_size; + *red = g_new (unsigned short, *size); + *green = g_new (unsigned short, *size); + *blue = g_new (unsigned short, *size); + + drmModeCrtcGetGamma (manager_kms->fd, crtc->crtc_id, *size, *red, *green, *blue); + + drmModeFreeCrtc (kms_crtc); +} + +static void +meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager, + MetaCRTC *crtc, + gsize size, + unsigned short *red, + unsigned short *green, + unsigned short *blue) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + + drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue); +} + +static void +meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms) +{ + ClutterBackend *backend; + CoglContext *cogl_context; + CoglDisplay *cogl_display; + CoglRenderer *cogl_renderer; + + backend = clutter_get_default_backend (); + cogl_context = clutter_backend_get_cogl_context (backend); + cogl_display = cogl_context_get_display (cogl_context); + cogl_renderer = cogl_display_get_renderer (cogl_display); + + manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer); +} + +static void +meta_monitor_manager_kms_finalize (GObject *object) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object); + + free_resources (manager_kms); + + G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object); +} + +static void +meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass) +{ + MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_monitor_manager_kms_finalize; + + manager_class->read_current = meta_monitor_manager_kms_read_current; + manager_class->read_edid = meta_monitor_manager_kms_read_edid; + manager_class->apply_configuration = meta_monitor_manager_kms_apply_configuration; + manager_class->set_power_save_mode = meta_monitor_manager_kms_set_power_save_mode; + manager_class->get_crtc_gamma = meta_monitor_manager_kms_get_crtc_gamma; + manager_class->set_crtc_gamma = meta_monitor_manager_kms_set_crtc_gamma; +} + diff --git a/src/backends/native/meta-monitor-manager-kms.h b/src/backends/native/meta-monitor-manager-kms.h new file mode 100644 index 0000000..4794e31 --- /dev/null +++ b/src/backends/native/meta-monitor-manager-kms.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef META_MONITOR_MANAGER_KMS_H +#define META_MONITOR_MANAGER_KMS_H + +#include "meta-monitor-manager.h" + +#define META_TYPE_MONITOR_MANAGER_KMS (meta_monitor_manager_kms_get_type ()) +#define META_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKms)) +#define META_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass)) +#define META_IS_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_KMS)) +#define META_IS_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_KMS)) +#define META_MONITOR_MANAGER_KMS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass)) + +typedef struct _MetaMonitorManagerKmsClass MetaMonitorManagerKmsClass; +typedef struct _MetaMonitorManagerKms MetaMonitorManagerKms; + +GType meta_monitor_manager_kms_get_type (void); + +#endif /* META_MONITOR_MANAGER_KMS_H */ diff --git a/src/backends/native/meta-weston-launch.c b/src/backends/native/meta-weston-launch.c new file mode 100644 index 0000000..a77b2ea --- /dev/null +++ b/src/backends/native/meta-weston-launch.c @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <config.h> + +#include <gio/gio.h> +#include <gio/gunixfdmessage.h> + +#include <clutter/clutter.h> +#include <clutter/egl/clutter-egl.h> +#include <clutter/evdev/clutter-evdev.h> + +#include <glib.h> +#include <sys/time.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdlib.h> +#include <sys/wait.h> + +#include <drm.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include "wayland/meta-wayland-private.h" +#include "meta-cursor-tracker-private.h" +#include "meta-weston-launch.h" + +struct _MetaLauncher +{ + GSocket *weston_launch; + + gboolean vt_switched; + + GMainContext *nested_context; + GMainLoop *nested_loop; + + GSource *inner_source; + GSource *outer_source; +}; + +static void handle_request_vt_switch (MetaLauncher *self); + +static gboolean +request_vt_switch_idle (gpointer user_data) +{ + handle_request_vt_switch (user_data); + + return FALSE; +} + +static gboolean +send_message_to_wl (MetaLauncher *self, + void *message, + gsize size, + GSocketControlMessage *out_cmsg, + GSocketControlMessage **in_cmsg, + GError **error) +{ + struct weston_launcher_reply reply; + GInputVector in_iov = { &reply, sizeof (reply) }; + GOutputVector out_iov = { message, size }; + GSocketControlMessage *out_all_cmsg[2]; + GSocketControlMessage **in_all_cmsg; + int flags = 0; + int i; + + out_all_cmsg[0] = out_cmsg; + out_all_cmsg[1] = NULL; + if (g_socket_send_message (self->weston_launch, NULL, + &out_iov, 1, + out_all_cmsg, -1, + flags, NULL, error) != (gssize)size) + return FALSE; + + if (g_socket_receive_message (self->weston_launch, NULL, + &in_iov, 1, + &in_all_cmsg, NULL, + &flags, NULL, error) != sizeof (reply)) + return FALSE; + + while (reply.header.opcode != ((struct weston_launcher_message*)message)->opcode) + { + /* There were events queued */ + g_assert ((reply.header.opcode & WESTON_LAUNCHER_EVENT) == WESTON_LAUNCHER_EVENT); + + /* This can never happen, because the only time mutter-launch can queue + this event is after confirming a VT switch, and we don't make requests + during that time. + + Note that getting this event would be really bad, because we would be + in the wrong loop/context. + */ + g_assert (reply.header.opcode != WESTON_LAUNCHER_SERVER_VT_ENTER); + + switch (reply.header.opcode) + { + case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH: + g_idle_add (request_vt_switch_idle, self); + break; + + default: + g_assert_not_reached (); + } + + if (g_socket_receive_message (self->weston_launch, NULL, + &in_iov, 1, + NULL, NULL, + &flags, NULL, error) != sizeof (reply)) + return FALSE; + } + + if (reply.ret != 0) + { + if (reply.ret == -1) + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Got failure from weston-launch"); + else + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-reply.ret), + "Got failure from weston-launch: %s", strerror (-reply.ret)); + + for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++) + g_object_unref (in_all_cmsg[i]); + g_free (in_all_cmsg); + + return FALSE; + } + + if (in_all_cmsg && in_all_cmsg[0]) + { + for (i = 1; in_all_cmsg[i]; i++) + g_object_unref (in_all_cmsg[i]); + *in_cmsg = in_all_cmsg[0]; + } + + g_free (in_all_cmsg); + return TRUE; +} + +static int +meta_launcher_open_device (MetaLauncher *self, + const char *name, + int flags, + GError **error) +{ + struct weston_launcher_open *message; + GSocketControlMessage *cmsg; + gboolean ok; + gsize size; + int *fds, n_fd; + int ret; + + size = sizeof (struct weston_launcher_open) + strlen (name) + 1; + message = g_malloc (size); + message->header.opcode = WESTON_LAUNCHER_OPEN; + message->flags = flags; + strcpy (message->path, name); + message->path[strlen(name)] = 0; + + ok = send_message_to_wl (self, message, size, NULL, &cmsg, error); + + if (ok) + { + g_assert (G_IS_UNIX_FD_MESSAGE (cmsg)); + + fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd); + g_assert (n_fd == 1); + + ret = fds[0]; + g_free (fds); + g_object_unref (cmsg); + } + else + ret = -1; + + g_free (message); + return ret; +} + +static void +meta_launcher_enter (MetaLauncher *launcher) +{ + ClutterBackend *backend; + CoglContext *cogl_context; + CoglDisplay *cogl_display; + + backend = clutter_get_default_backend (); + cogl_context = clutter_backend_get_cogl_context (backend); + cogl_display = cogl_context_get_display (cogl_context); + cogl_kms_display_queue_modes_reset (cogl_display); + + clutter_evdev_reclaim_devices (); + + { + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + + /* When we mode-switch back, we need to immediately queue a redraw + * in case nothing else queued one for us, and force the cursor to + * update. */ + + clutter_actor_queue_redraw (compositor->stage); + meta_cursor_tracker_force_update (compositor->seat->cursor_tracker); + } +} + +static void +meta_launcher_leave (MetaLauncher *launcher) +{ + clutter_evdev_release_devices (); +} + +static int +on_evdev_device_open (const char *path, + int flags, + gpointer user_data, + GError **error) +{ + MetaLauncher *launcher = user_data; + + return meta_launcher_open_device (launcher, path, flags, error); +} + +static void +on_evdev_device_close (int fd, + gpointer user_data) +{ + close (fd); +} + +static void +handle_vt_enter (MetaLauncher *launcher) +{ + g_assert (launcher->vt_switched); + + g_main_loop_quit (launcher->nested_loop); +} + +static void +handle_request_vt_switch (MetaLauncher *launcher) +{ + struct weston_launcher_message message; + GError *error; + gboolean ok; + + meta_launcher_leave (launcher); + + message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH; + + error = NULL; + ok = send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, &error); + if (!ok) { + g_warning ("Failed to acknowledge VT switch: %s", error->message); + g_error_free (error); + + return; + } + + g_assert (!launcher->vt_switched); + launcher->vt_switched = TRUE; + + /* We can't do anything at this point, because we don't + have input devices and we don't have the DRM master, + so let's run a nested busy loop until the VT is reentered */ + g_main_loop_run (launcher->nested_loop); + + g_assert (launcher->vt_switched); + launcher->vt_switched = FALSE; + + meta_launcher_enter (launcher); +} + +static gboolean +on_socket_readable (GSocket *socket, + GIOCondition condition, + gpointer user_data) +{ + MetaLauncher *launcher = user_data; + struct weston_launcher_event event; + gssize read; + GError *error; + + if ((condition & G_IO_IN) == 0) + return TRUE; + + error = NULL; + read = g_socket_receive (socket, (char*)&event, sizeof(event), NULL, &error); + if (read < (gssize)sizeof(event)) + { + g_warning ("Error reading from weston-launcher socket: %s", error->message); + g_error_free (error); + return TRUE; + } + + switch (event.header.opcode) + { + case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH: + handle_request_vt_switch (launcher); + break; + + case WESTON_LAUNCHER_SERVER_VT_ENTER: + handle_vt_enter (launcher); + break; + } + + return TRUE; +} + +static int +env_get_fd (const char *env) +{ + const char *value; + + value = g_getenv (env); + + if (value == NULL) + return -1; + else + return g_ascii_strtoll (value, NULL, 10); +} + +MetaLauncher * +meta_launcher_new (void) +{ + MetaLauncher *self = g_slice_new0 (MetaLauncher); + int launch_fd; + + launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK"); + if (launch_fd < 0) + g_error ("Invalid mutter-launch socket"); + + self->weston_launch = g_socket_new_from_fd (launch_fd, NULL); + + self->nested_context = g_main_context_new (); + self->nested_loop = g_main_loop_new (self->nested_context, FALSE); + + self->outer_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL); + g_source_set_callback (self->outer_source, (GSourceFunc)on_socket_readable, self, NULL); + g_source_attach (self->outer_source, NULL); + g_source_unref (self->outer_source); + + self->inner_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL); + g_source_set_callback (self->inner_source, (GSourceFunc)on_socket_readable, self, NULL); + g_source_attach (self->inner_source, self->nested_context); + g_source_unref (self->inner_source); + + clutter_evdev_set_device_callbacks (on_evdev_device_open, + on_evdev_device_close, + self); + +#if defined(CLUTTER_WINDOWING_EGL) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + { + GError *error = NULL; + int fd = meta_launcher_open_device (self, "/dev/dri/card0", O_RDWR, &error); + if (error) + g_error ("Failed to open /dev/dri/card0: %s", error->message); + + clutter_egl_set_kms_fd (fd); + } +#endif + + return self; +} + +void +meta_launcher_free (MetaLauncher *launcher) +{ + g_source_destroy (launcher->outer_source); + g_source_destroy (launcher->inner_source); + + g_main_loop_unref (launcher->nested_loop); + g_main_context_unref (launcher->nested_context); + + g_object_unref (launcher->weston_launch); + + g_slice_free (MetaLauncher, launcher); +} + +gboolean +meta_launcher_activate_vt (MetaLauncher *launcher, + signed char vt, + GError **error) +{ + struct weston_launcher_activate_vt message; + + message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT; + message.vt = vt; + + return send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, error); +} + diff --git a/src/backends/native/meta-weston-launch.h b/src/backends/native/meta-weston-launch.h new file mode 100644 index 0000000..b70faf8 --- /dev/null +++ b/src/backends/native/meta-weston-launch.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_WESTON_LAUNCH_H +#define META_WESTON_LAUNCH_H + +#include <glib-object.h> +#include "weston-launch.h" + +typedef struct _MetaLauncher MetaLauncher; + +MetaLauncher *meta_launcher_new (void); +void meta_launcher_free (MetaLauncher *self); + +gboolean meta_launcher_activate_vt (MetaLauncher *self, + signed char vt, + GError **error); +#endif diff --git a/src/backends/native/weston-launch.c b/src/backends/native/weston-launch.c new file mode 100644 index 0000000..ba1ed74 --- /dev/null +++ b/src/backends/native/weston-launch.c @@ -0,0 +1,711 @@ +/* + * Copyright © 2012 Benjamin Franzke + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <poll.h> +#include <errno.h> + +#include <error.h> +#include <getopt.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <sys/signalfd.h> +#include <signal.h> +#include <unistd.h> +#include <fcntl.h> +#include <limits.h> + +#include <termios.h> +#include <linux/vt.h> +#include <linux/major.h> +#include <linux/kd.h> + +#include <pwd.h> +#include <grp.h> + +#include <xf86drm.h> + +#include <systemd/sd-login.h> + +#include "weston-launch.h" + +#define MAX_ARGV_SIZE 256 +#define DRM_MAJOR 226 + +enum vt_state { + VT_HAS_VT, + VT_PENDING_CONFIRM, + VT_NOT_HAVE_VT, +}; + +struct weston_launch { + int tty; + int ttynr; + int sock[2]; + struct passwd *pw; + + int signalfd; + + pid_t child; + int verbose; + + struct termios terminal_attributes; + int kb_mode; + enum vt_state vt_state; + unsigned vt; + + int drm_fd; +}; + +union cmsg_data { unsigned char b[4]; int fd; }; + +static void quit (struct weston_launch *wl, int status); + +static int +weston_launch_allowed(struct weston_launch *wl) +{ + char *session, *seat; + int err; + + if (getuid() == 0) + return 1; + + err = sd_pid_get_session(getpid(), &session); + if (err == 0 && session) { + if (sd_session_is_active(session) && + sd_session_get_seat(session, &seat) == 0) { + free(seat); + free(session); + return 1; + } + free(session); + } + + return 0; +} + +static int +setup_launcher_socket(struct weston_launch *wl) +{ + if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0) + error(1, errno, "socketpair failed"); + + fcntl(wl->sock[0], F_SETFD, O_CLOEXEC); + + return 0; +} + +static int +setup_signals(struct weston_launch *wl) +{ + int ret; + sigset_t mask; + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_handler = SIG_DFL; + sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; + ret = sigaction(SIGCHLD, &sa, NULL); + assert(ret == 0); + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + sigaction(SIGHUP, &sa, NULL); + + ret = sigemptyset(&mask); + assert(ret == 0); + sigaddset(&mask, SIGCHLD); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGUSR1); + ret = sigprocmask(SIG_BLOCK, &mask, NULL); + assert(ret == 0); + + wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC); + if (wl->signalfd < 0) + return -errno; + + return 0; +} + +static void +setenv_fd(const char *env, int fd) +{ + char buf[32]; + + snprintf(buf, sizeof buf, "%d", fd); + setenv(env, buf, 1); +} + +static int +handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t len) +{ + struct weston_launcher_reply reply; + + reply.header.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH; + reply.ret = -1; + + if (wl->vt_state != VT_PENDING_CONFIRM) { + error(0, 0, "unexpected CONFIRM_VT_SWITCH"); + goto out; + } + + if (wl->drm_fd != -1) { + int ret; + + ret = drmDropMaster(wl->drm_fd); + if (ret < 0) { + fprintf(stderr, "failed to drop DRM master: %m\n"); + } else if (wl->verbose) { + fprintf(stderr, "dropped DRM master for VT switch\n"); + } + } + + wl->vt_state = VT_NOT_HAVE_VT; + ioctl(wl->tty, VT_RELDISP, 1); + + if (wl->verbose) + fprintf(stderr, "mutter-launcher: confirmed VT switch\n"); + + reply.ret = 0; + +out: + do { + len = send(wl->sock[0], &reply, sizeof reply, 0); + } while (len < 0 && errno == EINTR); + if (len < 0) + return -1; + + return 0; +} + +static int +handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len) +{ + struct weston_launcher_reply reply; + struct weston_launcher_activate_vt *message; + unsigned vt; + + reply.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT; + reply.ret = -1; + + if (len != sizeof(*message)) { + error(0, 0, "missing value in activate_vt request"); + goto out; + } + + message = msg->msg_iov->iov_base; + + /* Negative values mean that we're activating our own VT */ + if (message->vt > 0) + vt = message->vt; + else + vt = wl->vt; + + reply.ret = ioctl(wl->tty, VT_ACTIVATE, vt); + if (reply.ret < 0) + reply.ret = -errno; + + if (wl->verbose) + fprintf(stderr, "mutter-launch: activate VT, ret: %d\n", reply.ret); + +out: + do { + len = send(wl->sock[0], &reply, sizeof reply, 0); + } while (len < 0 && errno == EINTR); + if (len < 0) + return -1; + + return 0; +} + + +static int +handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len) +{ + struct weston_launcher_reply reply; + int fd = -1; + char control[CMSG_SPACE(sizeof(fd))]; + struct cmsghdr *cmsg; + struct stat s; + struct msghdr nmsg; + struct iovec iov; + struct weston_launcher_open *message; + union cmsg_data *data; + int dev_major; + + reply.header.opcode = WESTON_LAUNCHER_OPEN; + reply.ret = -1; + + message = msg->msg_iov->iov_base; + if ((size_t)len < sizeof(*message)) + goto err0; + + /* Ensure path is null-terminated */ + ((char *) message)[len-1] = '\0'; + + if (stat(message->path, &s) < 0) { + reply.ret = -errno; + goto err0; + } + + dev_major = major(s.st_rdev); + + if (dev_major != INPUT_MAJOR && + dev_major != DRM_MAJOR) { + fprintf(stderr, "Device %s is not an input or DRM device\n", + message->path); + reply.ret = -EPERM; + goto err0; + } + + if (dev_major == DRM_MAJOR && wl->drm_fd != -1) { + fprintf(stderr, "Already have a DRM device open\n"); + reply.ret = -EPERM; + goto err0; + } + + fd = open(message->path, message->flags); + if (fd < 0) { + fprintf(stderr, "Error opening device %s: %m\n", + message->path); + reply.ret = -errno; + goto err0; + } + + if (dev_major == DRM_MAJOR) { + wl->drm_fd = fd; + } + +err0: + memset(&nmsg, 0, sizeof nmsg); + nmsg.msg_iov = &iov; + nmsg.msg_iovlen = 1; + if (fd != -1) { + nmsg.msg_control = control; + nmsg.msg_controllen = sizeof control; + cmsg = CMSG_FIRSTHDR(&nmsg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + data = (union cmsg_data *) CMSG_DATA(cmsg); + data->fd = fd; + nmsg.msg_controllen = cmsg->cmsg_len; + reply.ret = 0; + } + iov.iov_base = &reply; + iov.iov_len = sizeof reply; + + if (wl->verbose) + fprintf(stderr, "mutter-launch: opened %s: ret: %d, fd: %d\n", + message->path, reply.ret, fd); + do { + len = sendmsg(wl->sock[0], &nmsg, 0); + } while (len < 0 && errno == EINTR); + + close(fd); + + if (len < 0) + return -1; + + return 0; +} + +static int +handle_socket_msg(struct weston_launch *wl) +{ + char control[CMSG_SPACE(sizeof(int))]; + char buf[BUFSIZ]; + struct msghdr msg; + struct iovec iov; + int ret = -1; + ssize_t len; + struct weston_launcher_message *message; + + memset(&msg, 0, sizeof(msg)); + iov.iov_base = buf; + iov.iov_len = sizeof buf; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control; + msg.msg_controllen = sizeof control; + + do { + len = recvmsg(wl->sock[0], &msg, 0); + } while (len < 0 && errno == EINTR); + + if (len < 1) + return -1; + + message = (void *) buf; + switch (message->opcode) { + case WESTON_LAUNCHER_OPEN: + ret = handle_open(wl, &msg, len); + break; + case WESTON_LAUNCHER_CONFIRM_VT_SWITCH: + ret = handle_confirm_vt_switch(wl, &msg, len); + break; + case WESTON_LAUNCHER_ACTIVATE_VT: + ret = handle_activate_vt(wl, &msg, len); + break; + } + + return ret; +} + +static void +tty_reset(struct weston_launch *wl) +{ + struct vt_mode mode = { 0 }; + + if (ioctl(wl->tty, KDSKBMODE, wl->kb_mode)) + fprintf(stderr, "failed to restore keyboard mode: %m\n"); + + if (ioctl(wl->tty, KDSETMODE, KD_TEXT)) + fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n"); + + if (tcsetattr(wl->tty, TCSANOW, &wl->terminal_attributes) < 0) + fprintf(stderr, "could not restore terminal to canonical mode\n"); + + mode.mode = VT_AUTO; + if (ioctl(wl->tty, VT_SETMODE, &mode) < 0) + fprintf(stderr, "could not reset vt handling\n"); +} + +static void +quit(struct weston_launch *wl, int status) +{ + if (wl->child > 0) + kill(wl->child, SIGKILL); + + close(wl->signalfd); + close(wl->sock[0]); + + if (wl->drm_fd > 0) + close(wl->drm_fd); + + tty_reset(wl); + + exit(status); +} + +static int +handle_vt_switch(struct weston_launch *wl) +{ + struct weston_launcher_event message; + ssize_t len; + + if (wl->vt_state == VT_HAS_VT) { + wl->vt_state = VT_PENDING_CONFIRM; + message.header.opcode = WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH; + } else if (wl->vt_state == VT_NOT_HAVE_VT) { + wl->vt_state = VT_HAS_VT; + ioctl(wl->tty, VT_RELDISP, VT_ACKACQ); + + if (wl->drm_fd != -1) { + int ret; + + ret = drmSetMaster(wl->drm_fd); + if (ret < 0) { + fprintf(stderr, "failed to become DRM master: %m\n"); + /* This is very, very bad, and the compositor will crash soon, + but oh well... */ + } else if (wl->verbose) { + fprintf(stderr, "became DRM master after VT switch\n"); + } + } + + message.header.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER; + } else + return -1; + + message.detail = 0; + + do { + len = send(wl->sock[0], &message, sizeof(message), 0); + } while (len < 0 && errno == EINTR); + + return 0; +} + + +static int +handle_signal(struct weston_launch *wl) +{ + struct signalfd_siginfo sig; + int pid, status, ret; + + if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) { + error(0, errno, "reading signalfd failed"); + return -1; + } + + switch (sig.ssi_signo) { + case SIGCHLD: + pid = waitpid(-1, &status, 0); + if (pid == wl->child) { + wl->child = 0; + if (WIFEXITED(status)) + ret = WEXITSTATUS(status); + else if (WIFSIGNALED(status)) + /* + * If weston dies because of signal N, we + * return 10+N. This is distinct from + * weston-launch dying because of a signal + * (128+N). + */ + ret = 10 + WTERMSIG(status); + else + ret = 0; + quit(wl, ret); + } + break; + case SIGTERM: + case SIGINT: + if (wl->child) + kill(wl->child, sig.ssi_signo); + break; + case SIGUSR1: + return handle_vt_switch(wl); + default: + return -1; + } + + return 0; +} + +static int +setup_tty(struct weston_launch *wl) +{ + struct stat buf; + struct termios raw_attributes; + struct vt_mode mode = { 0 }; + char *session; + char path[PATH_MAX]; + int ok; + + ok = sd_pid_get_session(getpid(), &session); + if (ok < 0) + error(1, -ok, "could not determine current session"); + + ok = sd_session_get_vt(session, &wl->vt); + if (ok < 0) + error(1, -ok, "could not determine current TTY"); + + snprintf(path, PATH_MAX, "/dev/tty%u", wl->vt); + wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC); + + if (wl->tty < 0) + error(1, errno, "failed to open tty"); + + if (fstat(wl->tty, &buf) < 0) + error(1, errno, "stat %s failed", path); + + if (major(buf.st_rdev) != TTY_MAJOR) + error(1, 0, "invalid tty device: %s", path); + + wl->ttynr = minor(buf.st_rdev); + + if (tcgetattr(wl->tty, &wl->terminal_attributes) < 0) + error(1, errno, "could not get terminal attributes"); + + /* Ignore control characters and disable echo */ + raw_attributes = wl->terminal_attributes; + cfmakeraw(&raw_attributes); + + /* Fix up line endings to be normal (cfmakeraw hoses them) */ + raw_attributes.c_oflag |= OPOST | OCRNL; + /* Don't generate ttou signals */ + raw_attributes.c_oflag &= ~TOSTOP; + + if (tcsetattr(wl->tty, TCSANOW, &raw_attributes) < 0) + error(1, errno, "could not put terminal into raw mode"); + + ioctl(wl->tty, KDGKBMODE, &wl->kb_mode); + ok = ioctl(wl->tty, KDSKBMODE, K_OFF); + if (ok < 0) { + ok = ioctl(wl->tty, KDSKBMODE, K_RAW); + if (ok < 0) + error(1, errno, "failed to set keyboard mode on tty"); + } + + ok = ioctl(wl->tty, KDSETMODE, KD_GRAPHICS); + if (ok < 0) + error(1, errno, "failed to set KD_GRAPHICS mode on tty"); + + wl->vt_state = VT_HAS_VT; + mode.mode = VT_PROCESS; + mode.relsig = SIGUSR1; + mode.acqsig = SIGUSR1; + ok = ioctl(wl->tty, VT_SETMODE, &mode); + if (ok < 0) + error(1, errno, "failed to take control of vt handling"); + + return 0; +} + +static void +drop_privileges(struct weston_launch *wl) +{ + if (setgid(wl->pw->pw_gid) < 0 || +#ifdef HAVE_INITGROUPS + initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 || +#endif + setuid(wl->pw->pw_uid) < 0) + error(1, errno, "dropping privileges failed"); +} + +static void +launch_compositor(struct weston_launch *wl, int argc, char *argv[]) +{ + char command[PATH_MAX]; + char *child_argv[MAX_ARGV_SIZE]; + sigset_t mask; + int i; + + if (wl->verbose) + printf("weston-launch: spawned weston with pid: %d\n", getpid()); + + drop_privileges(wl); + + setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]); + setenv("LD_LIBRARY_PATH", LIBDIR, 1); + unsetenv("DISPLAY"); + + /* Do not give our signal mask to the new process. */ + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGCHLD); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + + snprintf (command, PATH_MAX, "%s \"$@\"", argv[0]); + + child_argv[0] = wl->pw->pw_shell; + child_argv[1] = "-l"; + child_argv[2] = "-c"; + child_argv[3] = command; + for (i = 0; i < argc; ++i) + child_argv[4 + i] = argv[i]; + child_argv[4 + i] = NULL; + + execv(child_argv[0], child_argv); + error(1, errno, "exec failed"); +} + +static void +help(const char *name) +{ + fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name); + fprintf(stderr, " -u, --user Start session as specified username\n"); + fprintf(stderr, " -v, --verbose Be verbose\n"); + fprintf(stderr, " -h, --help Display this help message\n"); +} + +int +main(int argc, char *argv[]) +{ + struct weston_launch wl; + int i, c; + struct option opts[] = { + { "verbose", no_argument, NULL, 'v' }, + { "help", no_argument, NULL, 'h' }, + { 0, 0, NULL, 0 } + }; + + memset(&wl, 0, sizeof wl); + wl.drm_fd = -1; + + while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) { + switch (c) { + case 'v': + wl.verbose = 1; + break; + case 'h': + help("mutter-launch"); + exit(EXIT_FAILURE); + } + } + + if ((argc - optind) > (MAX_ARGV_SIZE - 6)) + error(1, E2BIG, "Too many arguments to pass to weston"); + + if (optind >= argc) + error(1, 0, "Expected program argument"); + + wl.pw = getpwuid(getuid()); + if (wl.pw == NULL) + error(1, errno, "failed to get username"); + + if (!weston_launch_allowed(&wl)) + error(1, 0, "Permission denied. You must run from an active and local (systemd) session."); + + if (setup_tty(&wl) < 0) + exit(EXIT_FAILURE); + + if (setup_launcher_socket(&wl) < 0) + exit(EXIT_FAILURE); + + if (setup_signals(&wl) < 0) + exit(EXIT_FAILURE); + + wl.child = fork(); + if (wl.child == -1) { + error(1, errno, "fork failed"); + exit(EXIT_FAILURE); + } + + if (wl.child == 0) + launch_compositor(&wl, argc - optind, argv + optind); + + close(wl.sock[1]); + + while (1) { + struct pollfd fds[2]; + int n; + + fds[0].fd = wl.sock[0]; + fds[0].events = POLLIN; + fds[1].fd = wl.signalfd; + fds[1].events = POLLIN; + + n = poll(fds, 2, -1); + if (n < 0) + error(0, errno, "poll failed"); + if (fds[0].revents & POLLIN) + handle_socket_msg(&wl); + if (fds[1].revents) + handle_signal(&wl); + } + + return 0; +} diff --git a/src/backends/native/weston-launch.h b/src/backends/native/weston-launch.h new file mode 100644 index 0000000..1e716c5 --- /dev/null +++ b/src/backends/native/weston-launch.h @@ -0,0 +1,68 @@ +/* + * Copyright © 2012 Benjamin Franzke + * 2013 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WESTON_LAUNCH_H_ +#define _WESTON_LAUNCH_H_ + +enum weston_launcher_message_type { + WESTON_LAUNCHER_REQUEST, + WESTON_LAUNCHER_EVENT, +}; + +enum weston_launcher_opcode { + WESTON_LAUNCHER_OPEN = (1 << 1 | WESTON_LAUNCHER_REQUEST), + WESTON_LAUNCHER_ACTIVATE_VT = (2 << 1 | WESTON_LAUNCHER_REQUEST), + WESTON_LAUNCHER_CONFIRM_VT_SWITCH = (3 << 1 | WESTON_LAUNCHER_REQUEST), +}; + +enum weston_launcher_server_opcode { + WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH = (1 << 1 | WESTON_LAUNCHER_EVENT), + WESTON_LAUNCHER_SERVER_VT_ENTER = (2 << 1 | WESTON_LAUNCHER_EVENT), +}; + +struct weston_launcher_message { + int opcode; +}; + +struct weston_launcher_open { + struct weston_launcher_message header; + int flags; + char path[0]; +}; + +struct weston_launcher_activate_vt { + struct weston_launcher_message header; + signed char vt; +}; + +struct weston_launcher_reply { + struct weston_launcher_message header; + int ret; +}; + +struct weston_launcher_event { + struct weston_launcher_message header; + int detail; /* unused, but makes sure replies and events are serialized the same */ +}; + +#endif diff --git a/src/backends/x11/meta-idle-monitor-xsync.c b/src/backends/x11/meta-idle-monitor-xsync.c new file mode 100644 index 0000000..25338a7 --- /dev/null +++ b/src/backends/x11/meta-idle-monitor-xsync.c @@ -0,0 +1,366 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#include "config.h" + +#include "meta-idle-monitor-xsync.h" +#include "meta-idle-monitor-private.h" + +#include <meta/util.h> +#include "display-private.h" + +#include <string.h> + +struct _MetaIdleMonitorXSync +{ + MetaIdleMonitor parent; + + GHashTable *alarms; + Display *display; + XSyncCounter counter; + XSyncAlarm user_active_alarm; +}; + +struct _MetaIdleMonitorXSyncClass +{ + MetaIdleMonitorClass parent_class; +}; + +typedef struct { + MetaIdleMonitorWatch base; + + XSyncAlarm xalarm; +} MetaIdleMonitorWatchXSync; + +G_DEFINE_TYPE (MetaIdleMonitorXSync, meta_idle_monitor_xsync, META_TYPE_IDLE_MONITOR) + +static gint64 +_xsyncvalue_to_int64 (XSyncValue value) +{ + return ((guint64) XSyncValueHigh32 (value)) << 32 + | (guint64) XSyncValueLow32 (value); +} + +#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32) + +static XSyncAlarm +_xsync_alarm_set (MetaIdleMonitorXSync *monitor_xsync, + XSyncTestType test_type, + guint64 interval, + gboolean want_events) +{ + XSyncAlarmAttributes attr; + XSyncValue delta; + guint flags; + + flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | + XSyncCAValue | XSyncCADelta | XSyncCAEvents; + + XSyncIntToValue (&delta, 0); + attr.trigger.counter = monitor_xsync->counter; + attr.trigger.value_type = XSyncAbsolute; + attr.delta = delta; + attr.events = want_events; + + GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value); + attr.trigger.test_type = test_type; + return XSyncCreateAlarm (monitor_xsync->display, flags, &attr); +} + +static void +ensure_alarm_rescheduled (Display *dpy, + XSyncAlarm alarm) +{ + XSyncAlarmAttributes attr; + + /* Some versions of Xorg have an issue where alarms aren't + * always rescheduled. Calling XSyncChangeAlarm, even + * without any attributes, will reschedule the alarm. */ + XSyncChangeAlarm (dpy, alarm, 0, &attr); +} + +static void +set_alarm_enabled (Display *dpy, + XSyncAlarm alarm, + gboolean enabled) +{ + XSyncAlarmAttributes attr; + attr.events = enabled; + XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr); +} + +static void +check_x11_watch (gpointer data, + gpointer user_data) +{ + MetaIdleMonitorWatchXSync *watch_xsync = data; + MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_xsync; + XSyncAlarm alarm = (XSyncAlarm) user_data; + + if (watch_xsync->xalarm != alarm) + return; + + _meta_idle_monitor_watch_fire (watch); +} + +static char * +counter_name_for_device (int device_id) +{ + if (device_id > 0) + return g_strdup_printf ("DEVICEIDLETIME %d", device_id); + + return g_strdup ("IDLETIME"); +} + +static XSyncCounter +find_idletime_counter (MetaIdleMonitorXSync *monitor_xsync) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_xsync); + int i; + int ncounters; + XSyncSystemCounter *counters; + XSyncCounter counter = None; + char *counter_name; + + counter_name = counter_name_for_device (monitor->device_id); + counters = XSyncListSystemCounters (monitor_xsync->display, &ncounters); + for (i = 0; i < ncounters; i++) + { + if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0) + { + counter = counters[i].counter; + break; + } + } + XSyncFreeSystemCounterList (counters); + g_free (counter_name); + + return counter; +} + +static void +init_xsync (MetaIdleMonitorXSync *monitor_xsync) +{ + monitor_xsync->counter = find_idletime_counter (monitor_xsync); + /* IDLETIME counter not found? */ + if (monitor_xsync->counter == None) + { + g_warning ("IDLETIME counter not found\n"); + return; + } + + monitor_xsync->user_active_alarm = _xsync_alarm_set (monitor_xsync, XSyncNegativeTransition, 1, FALSE); +} + +static void +meta_idle_monitor_xsync_dispose (GObject *object) +{ + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object); + + if (monitor_xsync->user_active_alarm != None) + { + XSyncDestroyAlarm (monitor_xsync->display, monitor_xsync->user_active_alarm); + monitor_xsync->user_active_alarm = None; + } + + g_clear_pointer (&monitor_xsync->alarms, g_hash_table_destroy); + + G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->dispose (object); +} + +static void +meta_idle_monitor_xsync_constructed (GObject *object) +{ + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object); + + g_assert (!meta_is_wayland_compositor ()); + + monitor_xsync->display = meta_get_display ()->xdisplay; + init_xsync (monitor_xsync); + + G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->constructed (object); +} + +static gint64 +meta_idle_monitor_xsync_get_idletime (MetaIdleMonitor *monitor) +{ + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor); + XSyncValue value; + + if (!XSyncQueryCounter (monitor_xsync->display, monitor_xsync->counter, &value)) + return -1; + + return _xsyncvalue_to_int64 (value); +} + +static gboolean +fire_watch_idle (gpointer data) +{ + MetaIdleMonitorWatch *watch = data; + + watch->idle_source_id = 0; + _meta_idle_monitor_watch_fire (watch); + + return FALSE; +} + +static guint32 +get_next_watch_serial (void) +{ + static guint32 serial = 0; + g_atomic_int_inc (&serial); + return serial; +} + +static void +free_watch (gpointer data) +{ + MetaIdleMonitorWatchXSync *watch_xsync = data; + MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_xsync; + MetaIdleMonitor *monitor = watch->monitor; + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor); + + g_object_ref (monitor); + + if (watch->idle_source_id) + { + g_source_remove (watch->idle_source_id); + watch->idle_source_id = 0; + } + + if (watch->notify != NULL) + watch->notify (watch->user_data); + + if (watch_xsync->xalarm != monitor_xsync->user_active_alarm && + watch_xsync->xalarm != None) + { + XSyncDestroyAlarm (monitor_xsync->display, watch_xsync->xalarm); + g_hash_table_remove (monitor_xsync->alarms, (gpointer) watch_xsync->xalarm); + } + + g_object_unref (monitor); + g_slice_free (MetaIdleMonitorWatchXSync, watch_xsync); +} + +static MetaIdleMonitorWatch * +meta_idle_monitor_xsync_make_watch (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor); + MetaIdleMonitorWatchXSync *watch_xsync; + MetaIdleMonitorWatch *watch; + + watch_xsync = g_slice_new0 (MetaIdleMonitorWatchXSync); + watch = (MetaIdleMonitorWatch *) watch_xsync; + + watch->monitor = monitor; + watch->id = get_next_watch_serial (); + watch->callback = callback; + watch->user_data = user_data; + watch->notify = notify; + watch->timeout_msec = timeout_msec; + + if (monitor_xsync->user_active_alarm != None) + { + if (timeout_msec != 0) + { + watch_xsync->xalarm = _xsync_alarm_set (monitor_xsync, XSyncPositiveTransition, timeout_msec, TRUE); + + g_hash_table_add (monitor_xsync->alarms, (gpointer) watch_xsync->xalarm); + + if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec) + watch->idle_source_id = g_idle_add (fire_watch_idle, watch); + } + else + { + watch_xsync->xalarm = monitor_xsync->user_active_alarm; + + set_alarm_enabled (monitor_xsync->display, monitor_xsync->user_active_alarm, TRUE); + } + } + + return watch; +} + +static void +meta_idle_monitor_xsync_class_init (MetaIdleMonitorXSyncClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass); + + object_class->dispose = meta_idle_monitor_xsync_dispose; + object_class->constructed = meta_idle_monitor_xsync_constructed; + + idle_monitor_class->get_idletime = meta_idle_monitor_xsync_get_idletime; + idle_monitor_class->make_watch = meta_idle_monitor_xsync_make_watch; +} + +static void +meta_idle_monitor_xsync_init (MetaIdleMonitorXSync *monitor_xsync) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_xsync); + + monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch); + monitor_xsync->alarms = g_hash_table_new (NULL, NULL); +} + +void +meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor *monitor, + XSyncAlarmNotifyEvent *alarm_event) +{ + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor); + XSyncAlarm alarm; + GList *watches; + gboolean has_alarm; + + if (alarm_event->state != XSyncAlarmActive) + return; + + alarm = alarm_event->alarm; + + has_alarm = FALSE; + + if (alarm == monitor_xsync->user_active_alarm) + { + set_alarm_enabled (monitor_xsync->display, + alarm, + FALSE); + has_alarm = TRUE; + } + else if (g_hash_table_contains (monitor_xsync->alarms, (gpointer) alarm)) + { + ensure_alarm_rescheduled (monitor_xsync->display, + alarm); + has_alarm = TRUE; + } + + if (has_alarm) + { + watches = g_hash_table_get_values (monitor->watches); + + g_list_foreach (watches, check_x11_watch, (gpointer) alarm); + g_list_free (watches); + } +} diff --git a/src/backends/x11/meta-idle-monitor-xsync.h b/src/backends/x11/meta-idle-monitor-xsync.h new file mode 100644 index 0000000..f8e88f0 --- /dev/null +++ b/src/backends/x11/meta-idle-monitor-xsync.h @@ -0,0 +1,49 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#ifndef META_IDLE_MONITOR_XSYNC_H +#define META_IDLE_MONITOR_XSYNC_H + +#include <glib-object.h> +#include <meta/meta-idle-monitor.h> + +#include <X11/Xlib.h> +#include <X11/extensions/sync.h> + +#define META_TYPE_IDLE_MONITOR_XSYNC (meta_idle_monitor_xsync_get_type ()) +#define META_IDLE_MONITOR_XSYNC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSync)) +#define META_IDLE_MONITOR_XSYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSyncClass)) +#define META_IS_IDLE_MONITOR_XSYNC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR_XSYNC)) +#define META_IS_IDLE_MONITOR_XSYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_IDLE_MONITOR_XSYNC)) +#define META_IDLE_MONITOR_XSYNC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSyncClass)) + +typedef struct _MetaIdleMonitorXSync MetaIdleMonitorXSync; +typedef struct _MetaIdleMonitorXSyncClass MetaIdleMonitorXSyncClass; + +GType meta_idle_monitor_xsync_get_type (void); + +void meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor *monitor, + XSyncAlarmNotifyEvent *xevent); + +void meta_idle_monitor_xsync_handle_xevent_all (XEvent *xevent); + +#endif /* META_IDLE_MONITOR_XSYNC_H */ diff --git a/src/core/monitor-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 857c3d3..5fbddd4 100644 --- a/src/core/monitor-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -25,6 +25,8 @@ #include "config.h" +#include "meta-monitor-manager-xrandr.h" + #include <string.h> #include <stdlib.h> #include <math.h> @@ -36,9 +38,8 @@ #include <meta/main.h> #include <meta/errors.h> -#include "monitor-private.h" - #include "edid.h" +#include "meta-monitor-config.h" #define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1) @@ -1017,7 +1018,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager, MetaOutput *old_outputs; MetaCRTC *old_crtcs; MetaMonitorMode *old_modes; - int n_old_outputs; + unsigned int n_old_outputs, n_old_modes; gboolean new_config; if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) @@ -1029,6 +1030,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager, old_outputs = manager->outputs; n_old_outputs = manager->n_outputs; old_modes = manager->modes; + n_old_modes = manager->n_modes; old_crtcs = manager->crtcs; manager->serial++; @@ -1068,7 +1070,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager, } meta_monitor_manager_free_output_array (old_outputs, n_old_outputs); - g_free (old_modes); + meta_monitor_manager_free_mode_array (old_modes, n_old_modes); g_free (old_crtcs); return TRUE; diff --git a/src/backends/x11/meta-monitor-manager-xrandr.h b/src/backends/x11/meta-monitor-manager-xrandr.h new file mode 100644 index 0000000..245a42e --- /dev/null +++ b/src/backends/x11/meta-monitor-manager-xrandr.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef META_MONITOR_MANAGER_XRANDR_H +#define META_MONITOR_MANAGER_XRANDR_H + +#include "meta-monitor-manager.h" + +#define META_TYPE_MONITOR_MANAGER_XRANDR (meta_monitor_manager_xrandr_get_type ()) +#define META_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandr)) +#define META_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass)) +#define META_IS_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_XRANDR)) +#define META_IS_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_XRANDR)) +#define META_MONITOR_MANAGER_XRANDR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass)) + +typedef struct _MetaMonitorManagerXrandrClass MetaMonitorManagerXrandrClass; +typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr; + +GType meta_monitor_manager_xrandr_get_type (void); + +#endif /* META_MONITOR_MANAGER_XRANDR_H */ diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index 18bcff6..ef0a534 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -11,35 +11,21 @@ #include "meta-window-actor-private.h" #include <clutter/clutter.h> -typedef struct _MetaCompScreen MetaCompScreen; - struct _MetaCompositor { MetaDisplay *display; guint repaint_func_id; - ClutterActor *shadow_src; - - MetaPlugin *modal_plugin; - gint64 server_time_query_time; gint64 server_time_offset; guint server_time_is_monotonic_time : 1; - guint show_redraw : 1; - guint debug : 1; guint no_mipmaps : 1; -}; -struct _MetaCompScreen -{ - MetaScreen *screen; - - ClutterActor *stage, *window_group, *top_window_group, *overlay_group; + ClutterActor *stage, *window_group, *top_window_group; ClutterActor *background_actor; GList *windows; - GHashTable *windows_by_xid; Window output; CoglOnscreen *onscreen; @@ -57,19 +43,17 @@ struct _MetaCompScreen /* Wait 2ms after vblank before starting to draw next frame */ #define META_SYNC_DELAY 2 -void meta_switch_workspace_completed (MetaScreen *screen); +void meta_switch_workspace_completed (MetaCompositor *compositor); -gboolean meta_begin_modal_for_plugin (MetaScreen *screen, +gboolean meta_begin_modal_for_plugin (MetaCompositor *compositor, MetaPlugin *plugin, MetaModalOptions options, guint32 timestamp); -void meta_end_modal_for_plugin (MetaScreen *screen, +void meta_end_modal_for_plugin (MetaCompositor *compositor, MetaPlugin *plugin, guint32 timestamp); gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display, gint64 monotonic_time); -void meta_check_end_modal (MetaScreen *screen); - #endif /* META_COMPOSITOR_PRIVATE_H */ diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 51e27f3..acb0599 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -65,7 +65,6 @@ #include <meta/window.h> #include "compositor-private.h" #include <meta/compositor-mutter.h> -#include "xprops.h" #include <meta/prefs.h> #include <meta/main.h> #include <meta/meta-background-actor.h> @@ -76,11 +75,17 @@ #include "window-private.h" /* to check window->hidden */ #include "display-private.h" /* for meta_display_lookup_x_window() */ #include "util-private.h" +#include "frame.h" #include <X11/extensions/shape.h> #include <X11/extensions/Xcomposite.h> -/* #define DEBUG_TRACE g_print */ -#define DEBUG_TRACE(X) +#include "wayland/meta-wayland-private.h" + +static gboolean +is_modal (MetaDisplay *display) +{ + return display->grab_op == META_GRAB_OP_COMPOSITOR; +} static inline gboolean composite_at_least_version (MetaDisplay *display, int maj, int min) @@ -94,41 +99,34 @@ composite_at_least_version (MetaDisplay *display, int maj, int min) return (major > maj || (major == maj && minor >= min)); } -static void sync_actor_stacking (MetaCompScreen *info); +static void sync_actor_stacking (MetaCompositor *compositor); static void -meta_finish_workspace_switch (MetaCompScreen *info) +meta_finish_workspace_switch (MetaCompositor *compositor) { GList *l; /* Finish hiding and showing actors for the new workspace */ - for (l = info->windows; l; l = l->next) + for (l = compositor->windows; l; l = l->next) meta_window_actor_sync_visibility (l->data); - /* - * Fix up stacking order in case the plugin messed it up. - */ - sync_actor_stacking (info); - -/* printf ("... FINISHED DESKTOP SWITCH\n"); */ - + /* Fix up stacking order. */ + sync_actor_stacking (compositor); } void -meta_switch_workspace_completed (MetaScreen *screen) +meta_switch_workspace_completed (MetaCompositor *compositor) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - /* FIXME -- must redo stacking order */ - info->switch_workspace_in_progress--; - if (info->switch_workspace_in_progress < 0) + compositor->switch_workspace_in_progress--; + if (compositor->switch_workspace_in_progress < 0) { g_warning ("Error in workspace_switch accounting!"); - info->switch_workspace_in_progress = 0; + compositor->switch_workspace_in_progress = 0; } - if (!info->switch_workspace_in_progress) - meta_finish_workspace_switch (info); + if (!compositor->switch_workspace_in_progress) + meta_finish_workspace_switch (compositor); } void @@ -138,47 +136,26 @@ meta_compositor_destroy (MetaCompositor *compositor) } static void -add_win (MetaWindow *window) -{ - MetaScreen *screen = meta_window_get_screen (window); - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - g_return_if_fail (info != NULL); - - meta_window_actor_new (window); - - sync_actor_stacking (info); -} - -static void process_damage (MetaCompositor *compositor, XDamageNotifyEvent *event, MetaWindow *window) { - MetaWindowActor *window_actor; - - if (window == NULL) - return; - - window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - if (window_actor == NULL) - return; - - meta_window_actor_process_damage (window_actor, event); + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); + meta_window_actor_process_x11_damage (window_actor, event); } static Window -get_output_window (MetaScreen *screen) +get_output_window (MetaCompositor *compositor) { - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - Window output, xroot; + MetaDisplay *display = compositor->display; + Display *xdisplay = display->xdisplay; + Window output, xroot; XWindowAttributes attr; - long event_mask; + long event_mask; unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; - xroot = meta_screen_get_xroot (screen); + xroot = display->screen->xroot; output = XCompositeGetOverlayWindow (xdisplay, xroot); meta_core_add_old_event_mask (xdisplay, output, &mask); @@ -203,6 +180,13 @@ get_output_window (MetaScreen *screen) return output; } +/* compat helper */ +static MetaCompositor * +get_compositor_for_screen (MetaScreen *screen) +{ + return screen->display->compositor; +} + /** * meta_get_stage_for_screen: * @screen: a #MetaScreen @@ -212,12 +196,8 @@ get_output_window (MetaScreen *screen) ClutterActor * meta_get_stage_for_screen (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info) - return NULL; - - return info->stage; + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->stage; } /** @@ -229,12 +209,8 @@ meta_get_stage_for_screen (MetaScreen *screen) ClutterActor * meta_get_window_group_for_screen (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info) - return NULL; - - return info->window_group; + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->window_group; } /** @@ -246,12 +222,8 @@ meta_get_window_group_for_screen (MetaScreen *screen) ClutterActor * meta_get_top_window_group_for_screen (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info) - return NULL; - - return info->top_window_group; + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->top_window_group; } /** @@ -263,31 +235,35 @@ meta_get_top_window_group_for_screen (MetaScreen *screen) GList * meta_get_window_actors (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info) - return NULL; - - return info->windows; + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->windows; } void meta_set_stage_input_region (MetaScreen *screen, XserverRegion region) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdpy = meta_display_get_xdisplay (display); - Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); + /* As a wayland compositor we can simply ignore all this trickery + * for setting an input region on the stage for capturing events in + * clutter since all input comes to us first and we get to choose + * who else sees them. + */ + if (!meta_is_wayland_compositor ()) + { + MetaDisplay *display = screen->display; + MetaCompositor *compositor = display->compositor; + Display *xdpy = meta_display_get_xdisplay (display); + Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); - XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); + XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); - /* It's generally a good heuristic that when a crossing event is generated because - * we reshape the overlay, we don't want it to affect focus-follows-mouse focus - - * it's not the user doing something, it's the environment changing under the user. - */ - meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy)); - XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region); + /* It's generally a good heuristic that when a crossing event is generated because + * we reshape the overlay, we don't want it to affect focus-follows-mouse focus - + * it's not the user doing something, it's the environment changing under the user. + */ + meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy)); + XFixesSetWindowShapeRegion (xdpy, compositor->output, ShapeInput, 0, 0, region); + } } void @@ -335,6 +311,9 @@ meta_stage_is_focused (MetaScreen *screen) ClutterStage *stage; Window window; + if (meta_is_wayland_compositor ()) + return TRUE; + stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen)); if (!stage) return FALSE; @@ -347,34 +326,18 @@ meta_stage_is_focused (MetaScreen *screen) return (screen->display->focus_xwindow == window); } -gboolean -meta_begin_modal_for_plugin (MetaScreen *screen, - MetaPlugin *plugin, - MetaModalOptions options, - guint32 timestamp) +static gboolean +begin_modal_x11 (MetaCompositor *compositor, + MetaPlugin *plugin, + MetaModalOptions options, + guint32 timestamp) { - /* To some extent this duplicates code in meta_display_begin_grab_op(), but there - * are significant differences in how we handle grabs that make it difficult to - * merge the two. - */ - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdpy = meta_display_get_xdisplay (display); - MetaCompositor *compositor = display->compositor; - ClutterStage *stage; - Window grab_window; - Cursor cursor = None; - gboolean pointer_grabbed = FALSE; - gboolean keyboard_grabbed = FALSE; - int result; - - stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen)); - if (!stage) - return FALSE; - - grab_window = clutter_x11_get_stage_window (stage); - - if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE) - return FALSE; + MetaDisplay *display = compositor->display; + Display *xdpy = meta_display_get_xdisplay (display); + Window grab_window = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); + int result; + gboolean pointer_grabbed = FALSE; + gboolean keyboard_grabbed = FALSE; if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0) { @@ -391,7 +354,7 @@ meta_begin_modal_for_plugin (MetaScreen *screen, META_VIRTUAL_CORE_POINTER_ID, grab_window, timestamp, - cursor, + None, XIGrabModeAsync, XIGrabModeAsync, False, /* owner_events */ &mask); @@ -424,14 +387,6 @@ meta_begin_modal_for_plugin (MetaScreen *screen, keyboard_grabbed = TRUE; } - display->grab_op = META_GRAB_OP_COMPOSITOR; - display->grab_window = NULL; - display->grab_screen = screen; - display->grab_have_pointer = TRUE; - display->grab_have_keyboard = TRUE; - - compositor->modal_plugin = plugin; - return TRUE; fail: @@ -443,45 +398,59 @@ meta_begin_modal_for_plugin (MetaScreen *screen, return FALSE; } -void -meta_end_modal_for_plugin (MetaScreen *screen, - MetaPlugin *plugin, - guint32 timestamp) +gboolean +meta_begin_modal_for_plugin (MetaCompositor *compositor, + MetaPlugin *plugin, + MetaModalOptions options, + guint32 timestamp) { - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdpy = meta_display_get_xdisplay (display); - MetaCompositor *compositor = display->compositor; + /* To some extent this duplicates code in meta_display_begin_grab_op(), but there + * are significant differences in how we handle grabs that make it difficult to + * merge the two. + */ + MetaDisplay *display = compositor->display; - g_return_if_fail (compositor->modal_plugin == plugin); + if (is_modal (display) || display->grab_op != META_GRAB_OP_NONE) + return FALSE; - XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp); - XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp); + if (!meta_is_wayland_compositor ()) + if (!begin_modal_x11 (compositor, plugin, options, timestamp)) + return FALSE; - display->grab_op = META_GRAB_OP_NONE; + display->grab_op = META_GRAB_OP_COMPOSITOR; display->grab_window = NULL; - display->grab_screen = NULL; - display->grab_have_pointer = FALSE; - display->grab_have_keyboard = FALSE; + display->grab_have_pointer = TRUE; + display->grab_have_keyboard = TRUE; - compositor->modal_plugin = NULL; + if (meta_is_wayland_compositor ()) + meta_display_sync_wayland_input_focus (display); + + return TRUE; } -/* This is used when reloading plugins to make sure we don't have - * a left-over modal grab for this screen. - */ void -meta_check_end_modal (MetaScreen *screen) +meta_end_modal_for_plugin (MetaCompositor *compositor, + MetaPlugin *plugin, + guint32 timestamp) { - MetaDisplay *display = meta_screen_get_display (screen); - MetaCompositor *compositor = display->compositor; + MetaDisplay *display = compositor->display; + Display *xdpy = meta_display_get_xdisplay (display); - if (compositor->modal_plugin && - meta_plugin_get_screen (compositor->modal_plugin) == screen) - { - meta_end_modal_for_plugin (screen, - compositor->modal_plugin, + g_return_if_fail (is_modal (display)); + + display->grab_op = META_GRAB_OP_NONE; + display->grab_window = NULL; + display->grab_have_pointer = FALSE; + display->grab_have_keyboard = FALSE; - CurrentTime); + if (meta_is_wayland_compositor ()) + { + meta_display_sync_wayland_input_focus (display); + } + else + { + XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp); + XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp); } } @@ -489,16 +458,18 @@ static void after_stage_paint (ClutterStage *stage, gpointer data) { - MetaCompScreen *info = (MetaCompScreen*) data; + MetaCompositor *compositor = data; GList *l; - for (l = info->windows; l; l = l->next) + for (l = compositor->windows; l; l = l->next) meta_window_actor_post_paint (l->data); + + if (meta_is_wayland_compositor ()) + meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ()); } static void -redirect_windows (MetaCompositor *compositor, - MetaScreen *screen) +redirect_windows (MetaScreen *screen) { MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); @@ -520,7 +491,7 @@ redirect_windows (MetaCompositor *compositor, */ while (TRUE) { - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual); XSync (xdisplay, FALSE); @@ -541,145 +512,152 @@ redirect_windows (MetaCompositor *compositor, } void -meta_compositor_manage_screen (MetaCompositor *compositor, - MetaScreen *screen) +meta_compositor_manage (MetaCompositor *compositor) { - MetaCompScreen *info; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - Window xwin; - gint width, height; - - /* Check if the screen is already managed */ - if (meta_screen_get_compositor_data (screen)) - return; + MetaDisplay *display = compositor->display; + Display *xdisplay = display->xdisplay; + MetaScreen *screen = display->screen; + Window xwin = 0; + gint width, height; + MetaWaylandCompositor *wayland_compositor; + + meta_screen_set_cm_selection (display->screen); + + /* We will have already created a stage if running as a wayland + * compositor... */ + if (meta_is_wayland_compositor ()) + { + wayland_compositor = meta_wayland_compositor_get_default (); + compositor->stage = wayland_compositor->stage; - info = g_new0 (MetaCompScreen, 1); - info->screen = screen; + meta_screen_get_size (screen, &width, &height); + clutter_actor_set_size (compositor->stage, width, height); + } + else + { + compositor->stage = clutter_stage_new (); - meta_screen_set_compositor_data (screen, info); + meta_screen_get_size (screen, &width, &height); + clutter_actor_realize (compositor->stage); - info->output = None; - info->windows = NULL; + xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); - meta_screen_set_cm_selection (screen); + XResizeWindow (xdisplay, xwin, width, height); - info->stage = clutter_stage_new (); + { + long event_mask; + unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; + XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; + XWindowAttributes attr; + + meta_core_add_old_event_mask (xdisplay, xwin, &mask); + + XISetMask (mask.mask, XI_KeyPress); + XISetMask (mask.mask, XI_KeyRelease); + XISetMask (mask.mask, XI_ButtonPress); + XISetMask (mask.mask, XI_ButtonRelease); + XISetMask (mask.mask, XI_Enter); + XISetMask (mask.mask, XI_Leave); + XISetMask (mask.mask, XI_FocusIn); + XISetMask (mask.mask, XI_FocusOut); + XISetMask (mask.mask, XI_Motion); + XIClearMask (mask.mask, XI_TouchBegin); + XIClearMask (mask.mask, XI_TouchEnd); + XIClearMask (mask.mask, XI_TouchUpdate); + XISelectEvents (xdisplay, xwin, &mask, 1); + + event_mask = ExposureMask | PropertyChangeMask | StructureNotifyMask; + if (XGetWindowAttributes (xdisplay, xwin, &attr)) + event_mask |= attr.your_event_mask; + + XSelectInput (xdisplay, xwin, event_mask); + } + } - clutter_stage_set_paint_callback (CLUTTER_STAGE (info->stage), + clutter_stage_set_paint_callback (CLUTTER_STAGE (compositor->stage), after_stage_paint, - info, + compositor, NULL); - clutter_stage_set_sync_delay (CLUTTER_STAGE (info->stage), META_SYNC_DELAY); - - meta_screen_get_size (screen, &width, &height); - clutter_actor_realize (info->stage); - - xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); - - XResizeWindow (xdisplay, xwin, width, height); - - { - long event_mask; - unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; - XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; - XWindowAttributes attr; - - meta_core_add_old_event_mask (xdisplay, xwin, &mask); - - XISetMask (mask.mask, XI_KeyPress); - XISetMask (mask.mask, XI_KeyRelease); - XISetMask (mask.mask, XI_ButtonPress); - XISetMask (mask.mask, XI_ButtonRelease); - XISetMask (mask.mask, XI_Enter); - XISetMask (mask.mask, XI_Leave); - XISetMask (mask.mask, XI_FocusIn); - XISetMask (mask.mask, XI_FocusOut); - XISetMask (mask.mask, XI_Motion); - XIClearMask (mask.mask, XI_TouchBegin); - XIClearMask (mask.mask, XI_TouchEnd); - XIClearMask (mask.mask, XI_TouchUpdate); - XISelectEvents (xdisplay, xwin, &mask, 1); - - event_mask = ExposureMask | PropertyChangeMask | StructureNotifyMask; - if (XGetWindowAttributes (xdisplay, xwin, &attr)) - event_mask |= attr.your_event_mask; - - XSelectInput (xdisplay, xwin, event_mask); - } - - info->window_group = meta_window_group_new (screen); - info->top_window_group = meta_window_group_new (screen); + clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY); - clutter_actor_add_child (info->stage, info->window_group); - clutter_actor_add_child (info->stage, info->top_window_group); + compositor->window_group = meta_window_group_new (screen); + compositor->top_window_group = meta_window_group_new (screen); - info->output = get_output_window (screen); - XReparentWindow (xdisplay, xwin, info->output, 0, 0); + clutter_actor_add_child (compositor->stage, compositor->window_group); + clutter_actor_add_child (compositor->stage, compositor->top_window_group); - /* Make sure there isn't any left-over output shape on the - * overlay window by setting the whole screen to be an - * output region. - * - * Note: there doesn't seem to be any real chance of that - * because the X server will destroy the overlay window - * when the last client using it exits. - */ - XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None); - - info->output = get_output_window (screen); - XReparentWindow (xdisplay, xwin, info->output, 0, 0); - - meta_empty_stage_input_region (screen); - - /* Make sure there isn't any left-over output shape on the - * overlay window by setting the whole screen to be an - * output region. - * - * Note: there doesn't seem to be any real chance of that - * because the X server will destroy the overlay window - * when the last client using it exits. - */ - XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None); + if (meta_is_wayland_compositor ()) + { + /* NB: When running as a wayland compositor we don't need an X + * composite overlay window, and we don't need to play any input + * region tricks to redirect events into clutter. */ + compositor->output = None; + } + else + { + compositor->output = get_output_window (compositor); + XReparentWindow (xdisplay, xwin, compositor->output, 0, 0); + + meta_empty_stage_input_region (screen); + + /* Make sure there isn't any left-over output shape on the + * overlay window by setting the whole screen to be an + * output region. + * + * Note: there doesn't seem to be any real chance of that + * because the X server will destroy the overlay window + * when the last client using it exits. + */ + XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None); - /* Map overlay window before redirecting windows offscreen so we catch their - * contents until we show the stage. - */ - XMapWindow (xdisplay, info->output); + /* Map overlay window before redirecting windows offscreen so we catch their + * contents until we show the stage. + */ + XMapWindow (xdisplay, compositor->output); + } - redirect_windows (compositor, screen); + redirect_windows (display->screen); - info->plugin_mgr = meta_plugin_manager_new (screen); + compositor->plugin_mgr = meta_plugin_manager_new (compositor); } void -meta_compositor_unmanage_screen (MetaCompositor *compositor, - MetaScreen *screen) +meta_compositor_unmanage (MetaCompositor *compositor) { - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - Window xroot = meta_screen_get_xroot (screen); - - /* This is the most important part of cleanup - we have to do this - * before giving up the window manager selection or the next - * window manager won't be able to redirect subwindows */ - XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual); + if (!meta_is_wayland_compositor ()) + { + MetaDisplay *display = compositor->display; + Display *xdisplay = meta_display_get_xdisplay (display); + Window xroot = display->screen->xroot; + + /* This is the most important part of cleanup - we have to do this + * before giving up the window manager selection or the next + * window manager won't be able to redirect subwindows */ + XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual); + } } -/* - * Shapes the cow so that the given window is exposed, - * when metaWindow is NULL it clears the shape again +/** + * meta_shape_cow_for_window: + * @compositor: A #MetaCompositor + * @window: (allow-none): A #MetaWindow to shape the COW for + * + * Sets an bounding shape on the COW so that the given window + * is exposed. If @window is %NULL it clears the shape again. + * + * Used so we can unredirect windows, by shaping away the part + * of the COW, letting the raw window be seen through below. */ static void -meta_shape_cow_for_window (MetaScreen *screen, - MetaWindow *metaWindow) +meta_shape_cow_for_window (MetaCompositor *compositor, + MetaWindow *window) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - Display *xdisplay = meta_display_get_xdisplay (meta_screen_get_display (screen)); + MetaDisplay *display = compositor->display; + Display *xdisplay = meta_display_get_xdisplay (display); - if (metaWindow == NULL) - XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None); + if (window == NULL) + XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None); else { XserverRegion output_region; @@ -687,14 +665,14 @@ meta_shape_cow_for_window (MetaScreen *screen, int width, height; MetaRectangle rect; - meta_window_get_frame_rect (metaWindow, &rect); + meta_window_get_frame_rect (window, &rect); window_bounds.x = rect.x; window_bounds.y = rect.y; window_bounds.width = rect.width; window_bounds.height = rect.height; - meta_screen_get_size (screen, &width, &height); + meta_screen_get_size (display->screen, &width, &height); screen_rect.x = 0; screen_rect.y = 0; screen_rect.width = width; @@ -703,46 +681,45 @@ meta_shape_cow_for_window (MetaScreen *screen, output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1); XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region); - XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, output_region); + XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, output_region); XFixesDestroyRegion (xdisplay, output_region); } } static void -set_unredirected_window (MetaCompScreen *info, +set_unredirected_window (MetaCompositor *compositor, MetaWindow *window) { - if (info->unredirected_window == window) + if (compositor->unredirected_window == window) return; - if (info->unredirected_window != NULL) + if (compositor->unredirected_window != NULL) { - MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (info->unredirected_window)); + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window)); meta_window_actor_set_unredirected (window_actor, FALSE); } - info->unredirected_window = window; + compositor->unredirected_window = window; - if (info->unredirected_window != NULL) + if (compositor->unredirected_window != NULL) { - MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (info->unredirected_window)); + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window)); meta_window_actor_set_unredirected (window_actor, TRUE); } - meta_shape_cow_for_window (info->screen, info->unredirected_window); + meta_shape_cow_for_window (compositor, compositor->unredirected_window); } void meta_compositor_add_window (MetaCompositor *compositor, MetaWindow *window) { - MetaScreen *screen = meta_window_get_screen (window); - MetaDisplay *display = meta_screen_get_display (screen); + MetaDisplay *display = compositor->display; - DEBUG_TRACE ("meta_compositor_add_window\n"); meta_error_trap_push (display); - add_win (window); + meta_window_actor_new (window); + sync_actor_stacking (compositor); meta_error_trap_pop (display); } @@ -751,20 +728,10 @@ void meta_compositor_remove_window (MetaCompositor *compositor, MetaWindow *window) { - MetaWindowActor *window_actor = NULL; - MetaScreen *screen; - MetaCompScreen *info; - - DEBUG_TRACE ("meta_compositor_remove_window\n"); - window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - if (!window_actor) - return; - - screen = meta_window_get_screen (window); - info = meta_screen_get_compositor_data (screen); + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - if (info->unredirected_window == window) - set_unredirected_window (info, NULL); + if (compositor->unredirected_window == window) + set_unredirected_window (compositor, NULL); meta_window_actor_destroy (window_actor); } @@ -774,13 +741,7 @@ meta_compositor_set_updates_frozen (MetaCompositor *compositor, MetaWindow *window, gboolean updates_frozen) { - MetaWindowActor *window_actor; - - DEBUG_TRACE ("meta_compositor_set_updates_frozen\n"); - window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - if (!window_actor) - return; - + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); meta_window_actor_set_updates_frozen (window_actor, updates_frozen); } @@ -789,13 +750,7 @@ meta_compositor_queue_frame_drawn (MetaCompositor *compositor, MetaWindow *window, gboolean no_delay_frame) { - MetaWindowActor *window_actor; - - DEBUG_TRACE ("meta_compositor_queue_frame_drawn\n"); - window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - if (!window_actor) - return; - + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame); } @@ -846,45 +801,87 @@ meta_compositor_window_opacity_changed (MetaCompositor *compositor, meta_window_actor_update_opacity (window_actor); } +void +meta_compositor_window_surface_changed (MetaCompositor *compositor, + MetaWindow *window) +{ + MetaWindowActor *window_actor; + window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); + if (!window_actor) + return; + + meta_window_actor_update_surface (window_actor); +} + +static gboolean +event_is_passive_button_grab (MetaDisplay *display, + XIDeviceEvent *device_event) +{ + /* see display.c for which events are passive button + grabs (meta_display_grab_window_buttons() and + meta_display_handle_events()) + we need to filter them here because normally they + would be sent to gtk+ (they are on gtk+ frame xwindow), + but we want to redirect them to clutter + */ + + if (device_event->evtype != XI_ButtonPress) + return FALSE; + + if (display->window_grab_modifiers == 0) + return FALSE; + + if ((device_event->mods.effective & display->window_grab_modifiers) != + display->window_grab_modifiers) + return FALSE; + + return device_event->detail < 4; +} + /* Clutter makes the assumption that there is only one X window * per stage, which is a valid assumption to make for a generic * application toolkit. As such, it will ignore any events sent * to the a stage that isn't its X window. * - * When a user clicks on what she thinks is the wallpaper, she - * is actually clicking on the guard window, which is an entirely - * separate top-level override-redirect window in the hierarchy. - * We want to recieve events on this guard window so that users - * can right-click on the background actor. We do this by telling - * Clutter a little white lie, by transforming clicks on the guard - * window to become clicks on the stage window, allowing Clutter - * to process the event normally. + * When running as an X window manager, we need to respond to + * events from lots of windows. Trick Clutter into translating + * these events by pretending we got an event on the stage window. */ static void -maybe_spoof_guard_window_event_as_stage_event (MetaCompScreen *info, - XEvent *event) +maybe_spoof_event_as_stage_event (MetaCompositor *compositor, + MetaWindow *window, + XEvent *event) { - MetaDisplay *display = meta_screen_get_display (info->screen); + MetaDisplay *display = compositor->display; if (event->type == GenericEvent && event->xcookie.extension == display->xinput_opcode) { XIEvent *input_event = (XIEvent *) event->xcookie.data; + XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event); - /* Only care about pointer events for now. */ switch (input_event->evtype) { case XI_Motion: case XI_ButtonPress: case XI_ButtonRelease: - { - XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event); - if (device_event->event == info->screen->guard_window) - { - Window xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); - device_event->event = xwin; - } - } + /* If this is a window frame, and we think GTK+ needs to handle the event, + let GTK+ handle it without mangling */ + if (window && window->frame && device_event->event == window->frame->xwindow && + (meta_grab_op_is_clicking (display->grab_op) || + (display->grab_op == META_GRAB_OP_NONE && !event_is_passive_button_grab (display, device_event)))) + break; + + case XI_KeyPress: + case XI_KeyRelease: + /* If this is a GTK+ widget, like a window menu, let GTK+ handle + * it as-is without mangling. */ + if (meta_ui_window_is_widget (display->screen->ui, device_event->event)) + break; + + device_event->event = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); + device_event->event_x = device_event->root_x; + device_event->event_y = device_event->root_y; break; default: break; @@ -904,55 +901,25 @@ meta_compositor_process_event (MetaCompositor *compositor, XEvent *event, MetaWindow *window) { - if (compositor->modal_plugin && is_grabbed_event (compositor->display, event)) + MetaDisplay *display = compositor->display; + + if (is_modal (display) && is_grabbed_event (display, event)) { - _meta_plugin_xevent_filter (compositor->modal_plugin, event); + meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event); /* We always consume events even if the plugin says it didn't handle them; * exclusive is exclusive */ return TRUE; } - if (window) - { - MetaCompScreen *info; - MetaScreen *screen; - - screen = meta_window_get_screen (window); - info = meta_screen_get_compositor_data (screen); - - if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event)) - { - DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n"); - return TRUE; - } - } - else - { - GSList *l; - - l = meta_display_get_screens (compositor->display); - - while (l) - { - MetaScreen *screen = l->data; - MetaCompScreen *info; - - info = meta_screen_get_compositor_data (screen); - - maybe_spoof_guard_window_event_as_stage_event (info, event); - - if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event)) - { - DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n"); - return TRUE; - } + if (!meta_is_wayland_compositor ()) + maybe_spoof_event_as_stage_event (compositor, window, event); - l = l->next; - } - } + if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event)) + return TRUE; - if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify) + if (!meta_is_wayland_compositor () && + event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify) { /* Core code doesn't handle damage events, so we need to extract the MetaWindow * ourselves @@ -963,13 +930,13 @@ meta_compositor_process_event (MetaCompositor *compositor, window = meta_display_lookup_x_window (compositor->display, xwin); } - DEBUG_TRACE ("meta_compositor_process_event (process_damage)\n"); - process_damage (compositor, (XDamageNotifyEvent *) event, window); + if (window) + process_damage (compositor, (XDamageNotifyEvent *) event, window); } /* Clutter needs to know about MapNotify events otherwise it will think the stage is invisible */ - if (event->type == MapNotify) + if (!meta_is_wayland_compositor () && event->type == MapNotify) clutter_x11_handle_event (event); /* The above handling is basically just "observing" the events, so we return @@ -981,15 +948,9 @@ meta_compositor_process_event (MetaCompositor *compositor, gboolean meta_compositor_filter_keybinding (MetaCompositor *compositor, - MetaScreen *screen, MetaKeyBinding *binding) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (info->plugin_mgr) - return meta_plugin_manager_filter_keybinding (info->plugin_mgr, binding); - - return FALSE; + return meta_plugin_manager_filter_keybinding (compositor->plugin_mgr, binding); } void @@ -998,11 +959,7 @@ meta_compositor_show_window (MetaCompositor *compositor, MetaCompEffect effect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - DEBUG_TRACE ("meta_compositor_show_window\n"); - if (!window_actor) - return; - - meta_window_actor_show (window_actor, effect); + meta_window_actor_show (window_actor, effect); } void @@ -1011,10 +968,6 @@ meta_compositor_hide_window (MetaCompositor *compositor, MetaCompEffect effect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - DEBUG_TRACE ("meta_compositor_hide_window\n"); - if (!window_actor) - return; - meta_window_actor_hide (window_actor, effect); } @@ -1025,10 +978,6 @@ meta_compositor_maximize_window (MetaCompositor *compositor, MetaRectangle *new_rect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - DEBUG_TRACE ("meta_compositor_maximize_window\n"); - if (!window_actor) - return; - meta_window_actor_maximize (window_actor, old_rect, new_rect); } @@ -1039,53 +988,40 @@ meta_compositor_unmaximize_window (MetaCompositor *compositor, MetaRectangle *new_rect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - DEBUG_TRACE ("meta_compositor_unmaximize_window\n"); - if (!window_actor) - return; - meta_window_actor_unmaximize (window_actor, old_rect, new_rect); } void meta_compositor_switch_workspace (MetaCompositor *compositor, - MetaScreen *screen, MetaWorkspace *from, MetaWorkspace *to, MetaMotionDirection direction) { - MetaCompScreen *info; - gint to_indx, from_indx; + gint to_indx, from_indx; - info = meta_screen_get_compositor_data (screen); to_indx = meta_workspace_index (to); from_indx = meta_workspace_index (from); - DEBUG_TRACE ("meta_compositor_switch_workspace\n"); + compositor->switch_workspace_in_progress++; - if (!info) /* During startup before manage_screen() */ - return; - - info->switch_workspace_in_progress++; - - if (!info->plugin_mgr || - !meta_plugin_manager_switch_workspace (info->plugin_mgr, - from_indx, - to_indx, - direction)) + if (!meta_plugin_manager_switch_workspace (compositor->plugin_mgr, + from_indx, + to_indx, + direction)) { - info->switch_workspace_in_progress--; + compositor->switch_workspace_in_progress--; /* We have to explicitely call this to fix up stacking order of the * actors; this is because the abs stacking position of actors does not * necessarily change during the window hiding/unhiding, only their * relative position toward the destkop window. */ - meta_finish_workspace_switch (info); + meta_finish_workspace_switch (compositor); } } static void -sync_actor_stacking (MetaCompScreen *info) +sync_actor_stacking (MetaCompositor *compositor) { GList *children; GList *expected_window_node; @@ -1101,7 +1037,7 @@ sync_actor_stacking (MetaCompScreen *info) * little effort to make sure we actually need to restack before * we go ahead and do it */ - children = clutter_actor_get_children (info->window_group); + children = clutter_actor_get_children (compositor->window_group); has_windows = FALSE; reordered = FALSE; @@ -1113,7 +1049,7 @@ sync_actor_stacking (MetaCompScreen *info) /* First we collect a list of all backgrounds, and check if they're at the * bottom. Then we check if the window actors are in the correct sequence */ backgrounds = NULL; - expected_window_node = info->windows; + expected_window_node = compositor->windows; for (old = children; old != NULL; old = old->next) { ClutterActor *actor = old->data; @@ -1151,7 +1087,7 @@ sync_actor_stacking (MetaCompScreen *info) * We reorder the actors even if they're not parented to the window group, * to allow stacking to work with intermediate actors (eg during effects) */ - for (tmp = g_list_last (info->windows); tmp != NULL; tmp = tmp->prev) + for (tmp = g_list_last (compositor->windows); tmp != NULL; tmp = tmp->prev) { ClutterActor *actor = tmp->data, *parent; @@ -1174,13 +1110,9 @@ sync_actor_stacking (MetaCompScreen *info) void meta_compositor_sync_stack (MetaCompositor *compositor, - MetaScreen *screen, GList *stack) { GList *old_stack; - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - DEBUG_TRACE ("meta_compositor_sync_stack\n"); /* This is painful because hidden windows that we are in the process * of animating out of existence. They'll be at the bottom of the @@ -1190,8 +1122,8 @@ meta_compositor_sync_stack (MetaCompositor *compositor, /* Sources: first window is the highest */ stack = g_list_copy (stack); /* The new stack of MetaWindow */ - old_stack = g_list_reverse (info->windows); /* The old stack of MetaWindowActor */ - info->windows = NULL; + old_stack = g_list_reverse (compositor->windows); /* The old stack of MetaWindowActor */ + compositor->windows = NULL; while (TRUE) { @@ -1255,13 +1187,13 @@ meta_compositor_sync_stack (MetaCompositor *compositor, * be at the front of at least one, hopefully it will be * near the front of the other.) */ - info->windows = g_list_prepend (info->windows, actor); + compositor->windows = g_list_prepend (compositor->windows, actor); stack = g_list_remove (stack, window); old_stack = g_list_remove (old_stack, actor); } - sync_actor_stacking (info); + sync_actor_stacking (compositor); } void @@ -1270,40 +1202,44 @@ meta_compositor_sync_window_geometry (MetaCompositor *compositor, gboolean did_placement) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - MetaScreen *screen = meta_window_get_screen (window); - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - DEBUG_TRACE ("meta_compositor_sync_window_geometry\n"); - g_return_if_fail (info); - - if (!window_actor) - return; - meta_window_actor_sync_actor_geometry (window_actor, did_placement); } void meta_compositor_sync_screen_size (MetaCompositor *compositor, - MetaScreen *screen, guint width, guint height) { - MetaDisplay *display = meta_screen_get_display (screen); - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - Display *xdisplay; - Window xwin; + MetaDisplay *display = compositor->display; + + if (meta_is_wayland_compositor ()) + { + /* FIXME: when we support a sliced stage, this is the place to do it + But! This is not the place to apply KMS config, here we only + notify Clutter/Cogl/GL that the framebuffer sizes changed. + + And because for now clutter does not do sliced, we use one + framebuffer the size of the whole screen, and when running on + bare metal MetaMonitorManager will do the necessary tricks to + show the right portions on the right screens. + */ - DEBUG_TRACE ("meta_compositor_sync_screen_size\n"); - g_return_if_fail (info); + clutter_actor_set_size (compositor->stage, width, height); + } + else + { + Display *xdisplay; + Window xwin; - xdisplay = meta_display_get_xdisplay (display); - xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); + xdisplay = meta_display_get_xdisplay (display); + xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); - XResizeWindow (xdisplay, xwin, width, height); + XResizeWindow (xdisplay, xwin, width, height); + } meta_verbose ("Changed size for stage on screen %d to %dx%d\n", - meta_screen_get_screen_number (screen), - width, height); + meta_screen_get_screen_number (display->screen), + width, height); } static void @@ -1312,7 +1248,7 @@ frame_callback (CoglOnscreen *onscreen, CoglFrameInfo *frame_info, void *user_data) { - MetaCompScreen *info = user_data; + MetaCompositor *compositor = user_data; GList *l; if (event == COGL_FRAME_EVENT_COMPLETE) @@ -1343,38 +1279,38 @@ frame_callback (CoglOnscreen *onscreen, presentation_time = 0; } - for (l = info->windows; l; l = l->next) + for (l = compositor->windows; l; l = l->next) meta_window_actor_frame_complete (l->data, frame_info, presentation_time); } } static void -pre_paint_windows (MetaCompScreen *info) +pre_paint_windows (MetaCompositor *compositor) { GList *l; MetaWindowActor *top_window; - if (info->onscreen == NULL) + if (compositor->onscreen == NULL) { - info->onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer ()); - info->frame_closure = cogl_onscreen_add_frame_callback (info->onscreen, - frame_callback, - info, - NULL); + compositor->onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer ()); + compositor->frame_closure = cogl_onscreen_add_frame_callback (compositor->onscreen, + frame_callback, + compositor, + NULL); } - if (info->windows == NULL) + if (compositor->windows == NULL) return; - top_window = g_list_last (info->windows)->data; + top_window = g_list_last (compositor->windows)->data; if (meta_window_actor_should_unredirect (top_window) && - info->disable_unredirect_count == 0) - set_unredirected_window (info, meta_window_actor_get_meta_window (top_window)); + compositor->disable_unredirect_count == 0) + set_unredirected_window (compositor, meta_window_actor_get_meta_window (top_window)); else - set_unredirected_window (info, NULL); + set_unredirected_window (compositor, NULL); - for (l = info->windows; l; l = l->next) + for (l = compositor->windows; l; l = l->next) meta_window_actor_pre_paint (l->data); } @@ -1382,19 +1318,7 @@ static gboolean meta_repaint_func (gpointer data) { MetaCompositor *compositor = data; - GSList *screens = meta_display_get_screens (compositor->display); - GSList *l; - - for (l = screens; l; l = l->next) - { - MetaScreen *screen = l->data; - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - if (!info) - continue; - - pre_paint_windows (info); - } - + pre_paint_windows (compositor); return TRUE; } @@ -1402,20 +1326,10 @@ static void on_shadow_factory_changed (MetaShadowFactory *factory, MetaCompositor *compositor) { - GSList *screens = meta_display_get_screens (compositor->display); GList *l; - GSList *sl; - - for (sl = screens; sl; sl = sl->next) - { - MetaScreen *screen = sl->data; - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - if (!info) - continue; - for (l = info->windows; l; l = l->next) - meta_window_actor_invalidate_shadow (l->data); - } + for (l = compositor->windows; l; l = l->next) + meta_window_actor_invalidate_shadow (l->data); } /** @@ -1458,9 +1372,8 @@ meta_compositor_new (MetaDisplay *display) Window meta_get_overlay_window (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - return info->output; + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->output; } /** @@ -1474,9 +1387,8 @@ meta_get_overlay_window (MetaScreen *screen) void meta_disable_unredirect_for_screen (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - if (info != NULL) - info->disable_unredirect_count = info->disable_unredirect_count + 1; + MetaCompositor *compositor = get_compositor_for_screen (screen); + compositor->disable_unredirect_count++; } /** @@ -1489,11 +1401,11 @@ meta_disable_unredirect_for_screen (MetaScreen *screen) void meta_enable_unredirect_for_screen (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - if (info != NULL && info->disable_unredirect_count == 0) + MetaCompositor *compositor = get_compositor_for_screen (screen); + if (compositor->disable_unredirect_count == 0) g_warning ("Called enable_unredirect_for_screen while unredirection is enabled."); - if (info != NULL && info->disable_unredirect_count > 0) - info->disable_unredirect_count = info->disable_unredirect_count - 1; + if (compositor->disable_unredirect_count > 0) + compositor->disable_unredirect_count--; } #define FLASH_TIME_MS 50 @@ -1590,28 +1502,16 @@ meta_compositor_monotonic_time_to_server_time (MetaDisplay *display, void meta_compositor_show_tile_preview (MetaCompositor *compositor, - MetaScreen *screen, MetaWindow *window, MetaRectangle *tile_rect, int tile_monitor_number) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info->plugin_mgr) - return; - - meta_plugin_manager_show_tile_preview (info->plugin_mgr, + meta_plugin_manager_show_tile_preview (compositor->plugin_mgr, window, tile_rect, tile_monitor_number); } void -meta_compositor_hide_tile_preview (MetaCompositor *compositor, - MetaScreen *screen) +meta_compositor_hide_tile_preview (MetaCompositor *compositor) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info->plugin_mgr) - return; - - meta_plugin_manager_hide_tile_preview (info->plugin_mgr); + meta_plugin_manager_hide_tile_preview (compositor->plugin_mgr); } diff --git a/src/compositor/meta-background.c b/src/compositor/meta-background.c index 4337f70..825ee90 100644 --- a/src/compositor/meta-background.c +++ b/src/compositor/meta-background.c @@ -26,8 +26,6 @@ #include <config.h> -#include <cogl/cogl-texture-pixmap-x11.h> - #include <clutter/clutter.h> #include "cogl-utils.h" @@ -755,88 +753,6 @@ set_filename (MetaBackground *self, priv->filename = g_strdup (filename); } -static Pixmap -get_still_frame_for_monitor (MetaScreen *screen, - int monitor) -{ - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - Window xroot = meta_screen_get_xroot (screen); - Pixmap pixmap; - GC gc; - XGCValues values; - MetaRectangle geometry; - int depth; - - meta_screen_get_monitor_geometry (screen, monitor, &geometry); - - depth = DefaultDepth (xdisplay, meta_screen_get_screen_number (screen)); - - pixmap = XCreatePixmap (xdisplay, - xroot, - geometry.width, geometry.height, depth); - - values.function = GXcopy; - values.plane_mask = AllPlanes; - values.fill_style = FillSolid; - values.subwindow_mode = IncludeInferiors; - - gc = XCreateGC (xdisplay, - xroot, - GCFunction | GCPlaneMask | GCFillStyle | GCSubwindowMode, - &values); - - XCopyArea (xdisplay, - xroot, pixmap, gc, - geometry.x, geometry.y, - geometry.width, geometry.height, - 0, 0); - - XFreeGC (xdisplay, gc); - - return pixmap; -} - -/** - * meta_background_load_still_frame: - * @self: the #MetaBackground - * - * Takes a screenshot of the desktop and uses it as the background - * source. - */ -void -meta_background_load_still_frame (MetaBackground *self) -{ - MetaBackgroundPrivate *priv = self->priv; - MetaDisplay *display = meta_screen_get_display (priv->screen); - Pixmap still_frame; - CoglTexture *texture; - CoglContext *context = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - GError *error = NULL; - - ensure_pipeline (self); - - unset_texture (self); - set_style (self, G_DESKTOP_BACKGROUND_STYLE_STRETCHED); - - still_frame = get_still_frame_for_monitor (priv->screen, priv->monitor); - XSync (meta_display_get_xdisplay (display), False); - - meta_error_trap_push (display); - texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (context, still_frame, FALSE, &error)); - meta_error_trap_pop (display); - - if (error != NULL) - { - g_warning ("Failed to create background texture from pixmap: %s", - error->message); - g_error_free (error); - return; - } - - set_texture (self, texture); -} - /** * meta_background_load_gradient: * @self: the #MetaBackground diff --git a/src/compositor/meta-plugin-manager.c b/src/compositor/meta-plugin-manager.c index 41589a3..8987e21 100644 --- a/src/compositor/meta-plugin-manager.c +++ b/src/compositor/meta-plugin-manager.c @@ -37,7 +37,7 @@ static GType plugin_type = G_TYPE_NONE; struct MetaPluginManager { - MetaScreen *screen; + MetaCompositor *compositor; MetaPlugin *plugin; }; @@ -91,7 +91,7 @@ on_confirm_display_change (MetaMonitorManager *monitors, } MetaPluginManager * -meta_plugin_manager_new (MetaScreen *screen) +meta_plugin_manager_new (MetaCompositor *compositor) { MetaPluginManager *plugin_mgr; MetaPluginClass *klass; @@ -99,8 +99,10 @@ meta_plugin_manager_new (MetaScreen *screen) MetaMonitorManager *monitors; plugin_mgr = g_new0 (MetaPluginManager, 1); - plugin_mgr->screen = screen; - plugin_mgr->plugin = plugin = g_object_new (plugin_type, "screen", screen, NULL); + plugin_mgr->compositor = compositor; + plugin_mgr->plugin = plugin = g_object_new (plugin_type, NULL); + + _meta_plugin_set_compositor (plugin, compositor); klass = META_PLUGIN_GET_CLASS (plugin); @@ -151,7 +153,7 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr, { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); + MetaDisplay *display = plugin_mgr->compositor->display; gboolean retval = FALSE; if (display->display_opening) @@ -165,8 +167,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr, retval = TRUE; meta_plugin_manager_kill_window_effects (plugin_mgr, actor); - - _meta_plugin_effect_started (plugin); klass->minimize (plugin, actor); } break; @@ -176,8 +176,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr, retval = TRUE; meta_plugin_manager_kill_window_effects (plugin_mgr, actor); - - _meta_plugin_effect_started (plugin); klass->map (plugin, actor); } break; @@ -185,7 +183,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr, if (klass->destroy) { retval = TRUE; - _meta_plugin_effect_started (plugin); klass->destroy (plugin, actor); } break; @@ -216,7 +213,7 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr, { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); + MetaDisplay *display = plugin_mgr->compositor->display; gboolean retval = FALSE; if (display->display_opening) @@ -230,8 +227,6 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr, retval = TRUE; meta_plugin_manager_kill_window_effects (plugin_mgr, actor); - - _meta_plugin_effect_started (plugin); klass->maximize (plugin, actor, target_x, target_y, target_width, target_height); @@ -243,8 +238,6 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr, retval = TRUE; meta_plugin_manager_kill_window_effects (plugin_mgr, actor); - - _meta_plugin_effect_started (plugin); klass->unmaximize (plugin, actor, target_x, target_y, target_width, target_height); @@ -273,7 +266,7 @@ meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr, { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); + MetaDisplay *display = plugin_mgr->compositor->display; gboolean retval = FALSE; if (display->display_opening) @@ -283,8 +276,6 @@ meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr, { retval = TRUE; meta_plugin_manager_kill_switch_workspace (plugin_mgr); - - _meta_plugin_effect_started (plugin); klass->switch_workspace (plugin, from, to, direction); } @@ -333,7 +324,7 @@ meta_plugin_manager_show_tile_preview (MetaPluginManager *plugin_mgr, { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); + MetaDisplay *display = plugin_mgr->compositor->display; if (display->display_opening) return FALSE; @@ -352,7 +343,7 @@ meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); + MetaDisplay *display = plugin_mgr->compositor->display; if (display->display_opening) return FALSE; diff --git a/src/compositor/meta-plugin-manager.h b/src/compositor/meta-plugin-manager.h index efc4deb..d814ee6 100644 --- a/src/compositor/meta-plugin-manager.h +++ b/src/compositor/meta-plugin-manager.h @@ -44,7 +44,7 @@ */ typedef struct MetaPluginManager MetaPluginManager; -MetaPluginManager * meta_plugin_manager_new (MetaScreen *screen); +MetaPluginManager * meta_plugin_manager_new (MetaCompositor *compositor); void meta_plugin_manager_load (const gchar *plugin_name); diff --git a/src/compositor/meta-plugin.c b/src/compositor/meta-plugin.c index d4d49b6..d7c4f11 100644 --- a/src/compositor/meta-plugin.c +++ b/src/compositor/meta-plugin.c @@ -30,6 +30,7 @@ #include "meta-plugin-manager.h" #include <meta/screen.h> #include <meta/display.h> +#include <meta/util.h> #include <string.h> #include <X11/Xlib.h> @@ -39,98 +40,22 @@ #include "compositor-private.h" #include "meta-window-actor-private.h" -#include "monitor-private.h" +#include "meta-monitor-manager.h" G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT); #define META_PLUGIN_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_PLUGIN, MetaPluginPrivate)) -enum -{ - PROP_0, - PROP_SCREEN, - PROP_DEBUG_MODE, -}; - struct _MetaPluginPrivate { - MetaScreen *screen; - - gint running; - gboolean debug : 1; + MetaCompositor *compositor; }; static void -meta_plugin_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaPluginPrivate *priv = META_PLUGIN (object)->priv; - - switch (prop_id) - { - case PROP_SCREEN: - priv->screen = g_value_get_object (value); - break; - case PROP_DEBUG_MODE: - priv->debug = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_plugin_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaPluginPrivate *priv = META_PLUGIN (object)->priv; - - switch (prop_id) - { - case PROP_SCREEN: - g_value_set_object (value, priv->screen); - break; - case PROP_DEBUG_MODE: - g_value_set_boolean (value, priv->debug); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void meta_plugin_class_init (MetaPluginClass *klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->set_property = meta_plugin_set_property; - gobject_class->get_property = meta_plugin_get_property; - - g_object_class_install_property (gobject_class, - PROP_SCREEN, - g_param_spec_object ("screen", - "MetaScreen", - "MetaScreen", - META_TYPE_SCREEN, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - PROP_DEBUG_MODE, - g_param_spec_boolean ("debug-mode", - "Debug Mode", - "Debug Mode", - FALSE, - G_PARAM_READABLE)); - - g_type_class_add_private (gobject_class, sizeof (MetaPluginPrivate)); + g_type_class_add_private (klass, sizeof (MetaPluginPrivate)); } static void @@ -139,22 +64,6 @@ meta_plugin_init (MetaPlugin *self) self->priv = META_PLUGIN_GET_PRIVATE (self); } -gboolean -meta_plugin_running (MetaPlugin *plugin) -{ - MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - - return (priv->running > 0); -} - -gboolean -meta_plugin_debug_mode (MetaPlugin *plugin) -{ - MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - - return priv->debug; -} - const MetaPluginInfo * meta_plugin_get_info (MetaPlugin *plugin) { @@ -166,31 +75,26 @@ meta_plugin_get_info (MetaPlugin *plugin) return NULL; } -/** - * _meta_plugin_effect_started: - * @plugin: the plugin - * - * Mark that an effect has started for the plugin. This is called - * internally by MetaPluginManager. - */ -void -_meta_plugin_effect_started (MetaPlugin *plugin) -{ - MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - - priv->running++; -} - gboolean _meta_plugin_xevent_filter (MetaPlugin *plugin, XEvent *xev) { MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); + /* When mutter is running as a wayland compositor, things like input + * events just come directly from clutter so it won't have disabled + * clutter's event retrieval and won't need to forward it events (if + * it did it would lead to recursion). Also when running as a + * wayland compositor we shouldn't be assuming that we're running + * with the clutter x11 backend. + */ + if (klass->xevent_filter && klass->xevent_filter (plugin, xev)) return TRUE; - else + else if (!meta_is_wayland_compositor ()) return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE; + else + return FALSE; } void @@ -198,15 +102,7 @@ meta_plugin_switch_workspace_completed (MetaPlugin *plugin) { MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - MetaScreen *screen = priv->screen; - - if (priv->running-- < 0) - { - g_warning ("Error in running effect accounting, adjusting."); - priv->running = 0; - } - - meta_switch_workspace_completed (screen); + meta_switch_workspace_completed (priv->compositor); } static void @@ -214,26 +110,6 @@ meta_plugin_window_effect_completed (MetaPlugin *plugin, MetaWindowActor *actor, unsigned long event) { - MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - - if (priv->running-- < 0) - { - g_warning ("Error in running effect accounting, adjusting."); - priv->running = 0; - } - - if (!actor) - { - const MetaPluginInfo *info; - const gchar *name = NULL; - - if (plugin && (info = meta_plugin_get_info (plugin))) - name = info->name; - - g_warning ("Plugin [%s] passed NULL for actor!", - name ? name : "unknown"); - } - meta_window_actor_effect_completed (actor, event); } @@ -300,7 +176,7 @@ meta_plugin_begin_modal (MetaPlugin *plugin, { MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - return meta_begin_modal_for_plugin (priv->screen, plugin, + return meta_begin_modal_for_plugin (priv->compositor, plugin, options, timestamp); } @@ -321,16 +197,14 @@ meta_plugin_end_modal (MetaPlugin *plugin, { MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - meta_end_modal_for_plugin (priv->screen, plugin, timestamp); + meta_end_modal_for_plugin (priv->compositor, plugin, timestamp); } /** * meta_plugin_get_screen: * @plugin: a #MetaPlugin * - * Gets the #MetaScreen corresponding to a plugin. Each plugin instance - * is associated with exactly one screen; if Metacity is managing - * multiple screens, multiple plugin instances will be created. + * Gets the #MetaScreen corresponding to a plugin. * * Return value: (transfer none): the #MetaScreen for the plugin */ @@ -339,7 +213,15 @@ meta_plugin_get_screen (MetaPlugin *plugin) { MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - return priv->screen; + return priv->compositor->display->screen; +} + +void +_meta_plugin_set_compositor (MetaPlugin *plugin, MetaCompositor *compositor) +{ + MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; + + priv->compositor = compositor; } void diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 082b1b1..bbcf0f9 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -28,6 +28,7 @@ #include <config.h> #include <meta/meta-shaped-texture.h> +#include <meta/util.h> #include "clutter-utils.h" #include "meta-texture-tower.h" @@ -42,8 +43,6 @@ static void meta_shaped_texture_dispose (GObject *object); static void meta_shaped_texture_paint (ClutterActor *actor); -static void meta_shaped_texture_pick (ClutterActor *actor, - const ClutterColor *color); static void meta_shaped_texture_get_preferred_width (ClutterActor *self, gfloat for_height, @@ -73,8 +72,6 @@ struct _MetaShapedTexturePrivate CoglTexture *texture; CoglTexture *mask_texture; - cairo_region_t *input_shape_region; - /* The region containing only fully opaque pixels */ cairo_region_t *opaque_region; @@ -98,7 +95,6 @@ meta_shaped_texture_class_init (MetaShapedTextureClass *klass) actor_class->get_preferred_width = meta_shaped_texture_get_preferred_width; actor_class->get_preferred_height = meta_shaped_texture_get_preferred_height; actor_class->paint = meta_shaped_texture_paint; - actor_class->pick = meta_shaped_texture_pick; actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume; g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate)); @@ -233,6 +229,54 @@ paint_clipped_rectangle (CoglFramebuffer *fb, } static void +set_cogl_texture (MetaShapedTexture *stex, + CoglTexture *cogl_tex) +{ + MetaShapedTexturePrivate *priv; + guint width, height; + + g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); + + priv = stex->priv; + + if (priv->texture) + cogl_object_unref (priv->texture); + + priv->texture = cogl_tex; + + if (cogl_tex != NULL) + { + cogl_object_ref (cogl_tex); + width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex)); + height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex)); + + if (width != priv->tex_width || + height != priv->tex_height) + { + priv->tex_width = width; + priv->tex_height = height; + + clutter_actor_queue_relayout (CLUTTER_ACTOR (stex)); + } + } + else + { + /* size changed to 0 going to an invalid handle */ + priv->tex_width = 0; + priv->tex_height = 0; + clutter_actor_queue_relayout (CLUTTER_ACTOR (stex)); + } + + /* NB: We don't queue a redraw of the actor here because we don't + * know how much of the buffer has changed with respect to the + * previous buffer. We only queue a redraw in response to surface + * damage. */ + + if (priv->create_mipmaps) + meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex); +} + +static void meta_shaped_texture_paint (ClutterActor *actor) { MetaShapedTexture *stex = (MetaShapedTexture *) actor; @@ -416,71 +460,6 @@ meta_shaped_texture_paint (ClutterActor *actor) } static void -meta_shaped_texture_pick (ClutterActor *actor, - const ClutterColor *color) -{ - MetaShapedTexture *stex = (MetaShapedTexture *) actor; - MetaShapedTexturePrivate *priv = stex->priv; - - if (!clutter_actor_should_pick_paint (actor) || - (priv->clip_region && cairo_region_is_empty (priv->clip_region))) - return; - - /* If there is no region then use the regular pick */ - if (priv->input_shape_region == NULL) - CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)->pick (actor, color); - else - { - int n_rects; - float *rectangles; - int i; - CoglPipeline *pipeline; - CoglContext *ctx; - CoglFramebuffer *fb; - CoglColor cogl_color; - - /* Note: We don't bother trying to intersect the pick and clip regions - * since needing to copy the region, do the intersection, and probably - * increase the number of rectangles seems more likely to have a negative - * effect. - * - * NB: Most of the time when just using rectangles for picking then - * picking shouldn't involve any rendering, and minimizing the number of - * rectangles has more benefit than reducing the area of the pick - * region. - */ - - n_rects = cairo_region_num_rectangles (priv->input_shape_region); - rectangles = g_alloca (sizeof (float) * 4 * n_rects); - - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - int pos = i * 4; - - cairo_region_get_rectangle (priv->input_shape_region, i, &rect); - - rectangles[pos] = rect.x; - rectangles[pos + 1] = rect.y; - rectangles[pos + 2] = rect.x + rect.width; - rectangles[pos + 3] = rect.y + rect.height; - } - - ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - fb = cogl_get_draw_framebuffer (); - - cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha); - - pipeline = cogl_pipeline_new (ctx); - cogl_pipeline_set_color (pipeline, &cogl_color); - - cogl_framebuffer_draw_rectangles (fb, pipeline, - rectangles, n_rects); - cogl_object_unref (pipeline); - } -} - -static void meta_shaped_texture_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, @@ -699,53 +678,6 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, } } -static void -set_cogl_texture (MetaShapedTexture *stex, - CoglTexture *cogl_tex) -{ - MetaShapedTexturePrivate *priv; - guint width, height; - - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - priv = stex->priv; - - if (priv->texture != NULL) - cogl_object_unref (priv->texture); - - priv->texture = cogl_tex; - - if (cogl_tex != NULL) - { - width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex)); - height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex)); - - if (width != priv->tex_width || - height != priv->tex_height) - { - priv->tex_width = width; - priv->tex_height = height; - - clutter_actor_queue_relayout (CLUTTER_ACTOR (stex)); - } - } - else - { - /* size changed to 0 going to an invalid texture */ - priv->tex_width = 0; - priv->tex_height = 0; - clutter_actor_queue_relayout (CLUTTER_ACTOR (stex)); - } - - /* NB: We don't queue a redraw of the actor here because we don't - * know how much of the buffer has changed with respect to the - * previous buffer. We only queue a redraw in response to surface - * damage. */ - - if (priv->create_mipmaps) - meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex); -} - /** * meta_shaped_texture_set_texture: * @stex: The #MetaShapedTexture @@ -774,41 +706,6 @@ meta_shaped_texture_get_texture (MetaShapedTexture *stex) } /** - * meta_shaped_texture_set_input_shape_region: - * @stex: a #MetaShapedTexture - * @shape_region: the region of the texture that should respond to - * input. - * - * Determines what region of the texture should accept input. For - * X based windows this is defined by the ShapeInput region of the - * window. - */ -void -meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex, - cairo_region_t *shape_region) -{ - MetaShapedTexturePrivate *priv; - - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - priv = stex->priv; - - if (priv->input_shape_region != NULL) - { - cairo_region_destroy (priv->input_shape_region); - priv->input_shape_region = NULL; - } - - if (shape_region != NULL) - { - cairo_region_reference (shape_region); - priv->input_shape_region = shape_region; - } - - clutter_actor_queue_redraw (CLUTTER_ACTOR (stex)); -} - -/** * meta_shaped_texture_set_opaque_region: * @stex: a #MetaShapedTexture * @opaque_region: (transfer full): the region of the texture that diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c new file mode 100644 index 0000000..e0c6ff7 --- /dev/null +++ b/src/compositor/meta-surface-actor-wayland.c @@ -0,0 +1,195 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#include "config.h" + +#include "meta-surface-actor-wayland.h" + +#include <cogl/cogl-wayland-server.h> +#include "meta-shaped-texture-private.h" + +#include "wayland/meta-wayland-private.h" + +struct _MetaSurfaceActorWaylandPrivate +{ + MetaWaylandSurface *surface; + MetaWaylandBuffer *buffer; + struct wl_listener buffer_destroy_listener; +}; +typedef struct _MetaSurfaceActorWaylandPrivate MetaSurfaceActorWaylandPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorWayland, meta_surface_actor_wayland, META_TYPE_SURFACE_ACTOR) + +static void +meta_surface_actor_handle_buffer_destroy (struct wl_listener *listener, void *data) +{ + MetaSurfaceActorWaylandPrivate *priv = wl_container_of (listener, priv, buffer_destroy_listener); + + /* If the buffer is destroyed while we're attached to it, + * we want to unset priv->buffer so we don't access freed + * memory. Keep the texture set however so the user doesn't + * see the window disappear. */ + priv->buffer = NULL; +} + +static void +meta_surface_actor_wayland_process_damage (MetaSurfaceActor *actor, + int x, int y, int width, int height) +{ + MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor); + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + + if (priv->buffer) + { + struct wl_resource *resource = priv->buffer->resource; + struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource); + + if (shm_buffer) + { + CoglTexture2D *texture = COGL_TEXTURE_2D (priv->buffer->texture); + cogl_wayland_texture_set_region_from_shm_buffer (texture, x, y, width, height, shm_buffer, x, y, 0, NULL); + } + + meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height); + } +} + +static void +meta_surface_actor_wayland_pre_paint (MetaSurfaceActor *actor) +{ +} + +static gboolean +meta_surface_actor_wayland_is_visible (MetaSurfaceActor *actor) +{ + /* TODO: ensure that the buffer isn't NULL, implement + * wayland mapping semantics */ + return TRUE; +} + +static gboolean +meta_surface_actor_wayland_should_unredirect (MetaSurfaceActor *actor) +{ + return FALSE; +} + +static void +meta_surface_actor_wayland_set_unredirected (MetaSurfaceActor *actor, + gboolean unredirected) +{ + /* Do nothing. In the future, we'll use KMS to set this + * up as a hardware overlay or something. */ +} + +static gboolean +meta_surface_actor_wayland_is_unredirected (MetaSurfaceActor *actor) +{ + return FALSE; +} + +static MetaWindow * +meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor) +{ + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (META_SURFACE_ACTOR_WAYLAND (actor)); + + return priv->surface->window; +} + +static void +meta_surface_actor_wayland_dispose (GObject *object) +{ + MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (object); + + meta_surface_actor_wayland_set_buffer (self, NULL); + + G_OBJECT_CLASS (meta_surface_actor_wayland_parent_class)->dispose (object); +} + +static void +meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass) +{ + MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage; + surface_actor_class->pre_paint = meta_surface_actor_wayland_pre_paint; + surface_actor_class->is_visible = meta_surface_actor_wayland_is_visible; + + surface_actor_class->should_unredirect = meta_surface_actor_wayland_should_unredirect; + surface_actor_class->set_unredirected = meta_surface_actor_wayland_set_unredirected; + surface_actor_class->is_unredirected = meta_surface_actor_wayland_is_unredirected; + + surface_actor_class->get_window = meta_surface_actor_wayland_get_window; + + object_class->dispose = meta_surface_actor_wayland_dispose; +} + +static void +meta_surface_actor_wayland_init (MetaSurfaceActorWayland *self) +{ + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + + priv->buffer_destroy_listener.notify = meta_surface_actor_handle_buffer_destroy; +} + +MetaSurfaceActor * +meta_surface_actor_wayland_new (MetaWaylandSurface *surface) +{ + MetaSurfaceActorWayland *self = g_object_new (META_TYPE_SURFACE_ACTOR_WAYLAND, NULL); + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + + g_assert (meta_is_wayland_compositor ()); + + priv->surface = surface; + + return META_SURFACE_ACTOR (self); +} + +void +meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self, + MetaWaylandBuffer *buffer) +{ + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + + if (priv->buffer) + wl_list_remove (&priv->buffer_destroy_listener.link); + + priv->buffer = buffer; + + if (priv->buffer) + { + wl_signal_add (&priv->buffer->destroy_signal, &priv->buffer_destroy_listener); + meta_shaped_texture_set_texture (stex, priv->buffer->texture); + } + else + meta_shaped_texture_set_texture (stex, NULL); +} + +MetaWaylandSurface * +meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self) +{ + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + return priv->surface; +} diff --git a/src/compositor/meta-surface-actor-wayland.h b/src/compositor/meta-surface-actor-wayland.h new file mode 100644 index 0000000..35058cc --- /dev/null +++ b/src/compositor/meta-surface-actor-wayland.h @@ -0,0 +1,66 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#ifndef __META_SURFACE_ACTOR_WAYLAND_H__ +#define __META_SURFACE_ACTOR_WAYLAND_H__ + +#include <glib-object.h> + +#include "meta-surface-actor.h" + +#include "wayland/meta-wayland.h" + +G_BEGIN_DECLS + +#define META_TYPE_SURFACE_ACTOR_WAYLAND (meta_surface_actor_wayland_get_type ()) +#define META_SURFACE_ACTOR_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWayland)) +#define META_SURFACE_ACTOR_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWaylandClass)) +#define META_IS_SURFACE_ACTOR_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND)) +#define META_IS_SURFACE_ACTOR_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR_WAYLAND)) +#define META_SURFACE_ACTOR_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWaylandClass)) + +typedef struct _MetaSurfaceActorWayland MetaSurfaceActorWayland; +typedef struct _MetaSurfaceActorWaylandClass MetaSurfaceActorWaylandClass; + +struct _MetaSurfaceActorWayland +{ + MetaSurfaceActor parent; +}; + +struct _MetaSurfaceActorWaylandClass +{ + MetaSurfaceActorClass parent_class; +}; + +GType meta_surface_actor_wayland_get_type (void); + +MetaSurfaceActor * meta_surface_actor_wayland_new (MetaWaylandSurface *surface); +MetaWaylandSurface * meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self); + +void meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self, + MetaWaylandBuffer *buffer); + +G_END_DECLS + +#endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */ diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c new file mode 100644 index 0000000..f6c9fb1 --- /dev/null +++ b/src/compositor/meta-surface-actor-x11.c @@ -0,0 +1,459 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Owen Taylor <otaylor@redhat.com> + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#include "config.h" + +#include "meta-surface-actor-x11.h" + +#include <X11/extensions/Xcomposite.h> +#include <cogl/cogl-texture-pixmap-x11.h> + +#include <meta/errors.h> +#include "window-private.h" +#include "meta-shaped-texture-private.h" +#include "meta-cullable.h" + +struct _MetaSurfaceActorX11Private +{ + MetaWindow *window; + + MetaDisplay *display; + + CoglTexture *texture; + Pixmap pixmap; + Damage damage; + + int last_width; + int last_height; + + /* This is used to detect fullscreen windows that need to be unredirected */ + guint full_damage_frames_count; + guint does_full_damage : 1; + + /* Other state... */ + guint received_damage : 1; + guint size_changed : 1; + + guint unredirected : 1; +}; +typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorX11, meta_surface_actor_x11, META_TYPE_SURFACE_ACTOR) + +static void +free_damage (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + + if (priv->damage == None) + return; + + meta_error_trap_push (display); + XDamageDestroy (xdisplay, priv->damage); + priv->damage = None; + meta_error_trap_pop (display); +} + +static void +detach_pixmap (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + + if (priv->pixmap == None) + return; + + /* Get rid of all references to the pixmap before freeing it; it's unclear whether + * you are supposed to be able to free a GLXPixmap after freeing the underlying + * pixmap, but it certainly doesn't work with current DRI/Mesa + */ + meta_shaped_texture_set_texture (stex, NULL); + cogl_flush (); + + meta_error_trap_push (display); + XFreePixmap (xdisplay, priv->pixmap); + priv->pixmap = None; + meta_error_trap_pop (display); + + cogl_object_unref (priv->texture); + priv->texture = NULL; +} + +static void +set_pixmap (MetaSurfaceActorX11 *self, + Pixmap pixmap) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + CoglTexture *texture; + + g_assert (priv->pixmap == None); + priv->pixmap = pixmap; + + texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->pixmap, FALSE, NULL)); + + if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture)))) + g_warning ("NOTE: Not using GLX TFP!\n"); + + priv->texture = texture; + meta_shaped_texture_set_texture (stex, texture); +} + +static void +update_pixmap (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + + if (priv->size_changed) + { + detach_pixmap (self); + priv->size_changed = FALSE; + } + + if (priv->pixmap == None) + { + Pixmap new_pixmap; + Window xwindow = meta_window_get_toplevel_xwindow (priv->window); + + meta_error_trap_push (display); + new_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow); + + if (meta_error_trap_pop_with_return (display) != Success) + { + /* Probably a BadMatch if the window isn't viewable; we could + * GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync + * to avoid this, but there's no reason to take two round trips + * when one will do. (We need that Sync if we want to handle failures + * for any reason other than !viewable. That's unlikely, but maybe + * we'll BadAlloc or something.) + */ + new_pixmap = None; + } + + if (new_pixmap == None) + { + meta_verbose ("Unable to get named pixmap for %s\n", + meta_window_get_description (priv->window)); + return; + } + + set_pixmap (self, new_pixmap); + } +} + +static gboolean +is_visible (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + return (priv->pixmap != None) && !priv->unredirected; +} + +static void +damage_area (MetaSurfaceActorX11 *self, + int x, int y, int width, int height) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + if (!is_visible (self)) + return; + + cogl_texture_pixmap_x11_update_area (priv->texture, x, y, width, height); + meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height); +} + +static void +meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor, + int x, int y, int width, int height) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + priv->received_damage = TRUE; + + if (meta_window_is_fullscreen (priv->window) && !priv->unredirected && !priv->does_full_damage) + { + MetaRectangle window_rect; + meta_window_get_frame_rect (priv->window, &window_rect); + + if (window_rect.x == x && + window_rect.y == y && + window_rect.width == width && + window_rect.height == height) + priv->full_damage_frames_count++; + else + priv->full_damage_frames_count = 0; + + if (priv->full_damage_frames_count >= 100) + priv->does_full_damage = TRUE; + } + + /* Drop damage event for unredirected windows */ + if (priv->unredirected) + return; + + damage_area (self, x, y, width, height); +} + +static void +meta_surface_actor_x11_pre_paint (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + + if (priv->received_damage) + { + meta_error_trap_push (display); + XDamageSubtract (xdisplay, priv->damage, None, None); + meta_error_trap_pop (display); + + /* We need to make sure that any X drawing that happens before the + * XDamageSubtract() above is visible to subsequent GL rendering; + * the only standardized way to do this is EXT_x11_sync_object, + * which isn't yet widely available. For now, we count on details + * of Xorg and the open source drivers, and hope for the best + * otherwise. + * + * Xorg and open source driver specifics: + * + * The X server makes sure to flush drawing to the kernel before + * sending out damage events, but since we use DamageReportBoundingBox + * there may be drawing between the last damage event and the + * XDamageSubtract() that needs to be flushed as well. + * + * Xorg always makes sure that drawing is flushed to the kernel + * before writing events or responses to the client, so any round trip + * request at this point is sufficient to flush the GLX buffers. + */ + XSync (xdisplay, False); + + priv->received_damage = FALSE; + } + + update_pixmap (self); +} + +static gboolean +meta_surface_actor_x11_is_visible (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + return is_visible (self); +} + +static gboolean +meta_surface_actor_x11_should_unredirect (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + MetaWindow *window = priv->window; + + if (meta_window_requested_dont_bypass_compositor (window)) + return FALSE; + + if (window->opacity != 0xFF) + return FALSE; + + if (window->shape_region != NULL) + return FALSE; + + if (meta_surface_actor_is_argb32 (actor) && !meta_window_requested_bypass_compositor (window)) + return FALSE; + + if (!meta_window_is_monitor_sized (window)) + return FALSE; + + if (meta_window_requested_bypass_compositor (window)) + return TRUE; + + if (meta_window_is_override_redirect (window)) + return TRUE; + + if (priv->does_full_damage) + return TRUE; + + return FALSE; +} + +static void +sync_unredirected (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + Window xwindow = meta_window_get_toplevel_xwindow (priv->window); + + meta_error_trap_push (display); + + if (priv->unredirected) + { + detach_pixmap (self); + XCompositeUnredirectWindow (xdisplay, xwindow, CompositeRedirectManual); + } + else + { + XCompositeRedirectWindow (xdisplay, xwindow, CompositeRedirectManual); + } + + meta_error_trap_pop (display); +} + +static void +meta_surface_actor_x11_set_unredirected (MetaSurfaceActor *actor, + gboolean unredirected) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + if (priv->unredirected == unredirected) + return; + + priv->unredirected = unredirected; + sync_unredirected (self); +} + +static gboolean +meta_surface_actor_x11_is_unredirected (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + return priv->unredirected; +} + +static void +meta_surface_actor_x11_dispose (GObject *object) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (object); + + detach_pixmap (self); + free_damage (self); + + G_OBJECT_CLASS (meta_surface_actor_x11_parent_class)->dispose (object); +} + +static MetaWindow * +meta_surface_actor_x11_get_window (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (META_SURFACE_ACTOR_X11 (actor)); + + return priv->window; +} + +static void +meta_surface_actor_x11_class_init (MetaSurfaceActorX11Class *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass); + + object_class->dispose = meta_surface_actor_x11_dispose; + + surface_actor_class->process_damage = meta_surface_actor_x11_process_damage; + surface_actor_class->pre_paint = meta_surface_actor_x11_pre_paint; + surface_actor_class->is_visible = meta_surface_actor_x11_is_visible; + + surface_actor_class->should_unredirect = meta_surface_actor_x11_should_unredirect; + surface_actor_class->set_unredirected = meta_surface_actor_x11_set_unredirected; + surface_actor_class->is_unredirected = meta_surface_actor_x11_is_unredirected; + + surface_actor_class->get_window = meta_surface_actor_x11_get_window; +} + +static void +meta_surface_actor_x11_init (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + priv->last_width = -1; + priv->last_height = -1; +} + +static void +create_damage (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + Display *xdisplay = meta_display_get_xdisplay (priv->display); + Window xwindow = meta_window_get_toplevel_xwindow (priv->window); + + priv->damage = XDamageCreate (xdisplay, xwindow, XDamageReportBoundingBox); +} + +static void +window_decorated_notify (MetaWindow *window, + GParamSpec *pspec, + gpointer user_data) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data); + + free_damage (self); + create_damage (self); +} + +MetaSurfaceActor * +meta_surface_actor_x11_new (MetaWindow *window) +{ + MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = meta_window_get_display (window); + + g_assert (!meta_is_wayland_compositor ()); + + priv->window = window; + priv->display = display; + + create_damage (self); + g_signal_connect_object (priv->window, "notify::decorated", + G_CALLBACK (window_decorated_notify), self, 0); + + priv->unredirected = FALSE; + sync_unredirected (self); + + clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE); + return META_SURFACE_ACTOR (self); +} + +void +meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, + int width, int height) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + if (priv->last_width == width && + priv->last_height == height) + return; + + priv->size_changed = TRUE; + priv->last_width = width; + priv->last_height = height; +} diff --git a/src/compositor/meta-surface-actor-x11.h b/src/compositor/meta-surface-actor-x11.h new file mode 100644 index 0000000..0e692ee --- /dev/null +++ b/src/compositor/meta-surface-actor-x11.h @@ -0,0 +1,69 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Owen Taylor <otaylor@redhat.com> + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#ifndef __META_SURFACE_ACTOR_X11_H__ +#define __META_SURFACE_ACTOR_X11_H__ + +#include <glib-object.h> + +#include "meta-surface-actor.h" + +#include <X11/extensions/Xdamage.h> + +#include <meta/display.h> +#include <meta/window.h> + +G_BEGIN_DECLS + +#define META_TYPE_SURFACE_ACTOR_X11 (meta_surface_actor_x11_get_type ()) +#define META_SURFACE_ACTOR_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11)) +#define META_SURFACE_ACTOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11Class)) +#define META_IS_SURFACE_ACTOR_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR_X11)) +#define META_IS_SURFACE_ACTOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR_X11)) +#define META_SURFACE_ACTOR_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11Class)) + +typedef struct _MetaSurfaceActorX11 MetaSurfaceActorX11; +typedef struct _MetaSurfaceActorX11Class MetaSurfaceActorX11Class; + +struct _MetaSurfaceActorX11 +{ + MetaSurfaceActor parent; +}; + +struct _MetaSurfaceActorX11Class +{ + MetaSurfaceActorClass parent_class; +}; + +GType meta_surface_actor_x11_get_type (void); + +MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window); + +void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, + int width, int height); + +G_END_DECLS + +#endif /* __META_SURFACE_ACTOR_X11_H__ */ diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c new file mode 100644 index 0000000..3e7db6b --- /dev/null +++ b/src/compositor/meta-surface-actor.c @@ -0,0 +1,338 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/** + * SECTION:meta-surface-actor + * @title: MetaSurfaceActor + * @short_description: An actor representing a surface in the scene graph + * + * A surface can be either a shaped texture, or a group of shaped texture, + * used to draw the content of a window. + */ + +#include <config.h> + +#include "meta-surface-actor.h" + +#include <clutter/clutter.h> +#include <meta/meta-shaped-texture.h> +#include "meta-cullable.h" +#include "meta-shaped-texture-private.h" + +struct _MetaSurfaceActorPrivate +{ + MetaShapedTexture *texture; + + cairo_region_t *input_region; + + /* Freeze/thaw accounting */ + guint needs_damage_all : 1; + guint frozen : 1; +}; + +static void cullable_iface_init (MetaCullableInterface *iface); + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR, + G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); + +enum { + REPAINT_SCHEDULED, + + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL]; + +gboolean +meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self, + cairo_rectangle_int_t *unobscured_bounds) +{ + MetaSurfaceActorPrivate *priv = self->priv; + return meta_shaped_texture_get_unobscured_bounds (priv->texture, unobscured_bounds); +} + +static void +meta_surface_actor_pick (ClutterActor *actor, + const ClutterColor *color) +{ + MetaSurfaceActor *self = META_SURFACE_ACTOR (actor); + MetaSurfaceActorPrivate *priv = self->priv; + + if (!clutter_actor_should_pick_paint (actor)) + return; + + /* If there is no region then use the regular pick */ + if (priv->input_region == NULL) + CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->pick (actor, color); + else + { + int n_rects; + float *rectangles; + int i; + CoglPipeline *pipeline; + CoglContext *ctx; + CoglFramebuffer *fb; + CoglColor cogl_color; + + n_rects = cairo_region_num_rectangles (priv->input_region); + rectangles = g_alloca (sizeof (float) * 4 * n_rects); + + for (i = 0; i < n_rects; i++) + { + cairo_rectangle_int_t rect; + int pos = i * 4; + + cairo_region_get_rectangle (priv->input_region, i, &rect); + + rectangles[pos + 0] = rect.x; + rectangles[pos + 1] = rect.y; + rectangles[pos + 2] = rect.x + rect.width; + rectangles[pos + 3] = rect.y + rect.height; + } + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + fb = cogl_get_draw_framebuffer (); + + cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha); + + pipeline = cogl_pipeline_new (ctx); + cogl_pipeline_set_color (pipeline, &cogl_color); + cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects); + cogl_object_unref (pipeline); + } +} + +static void +meta_surface_actor_dispose (GObject *object) +{ + MetaSurfaceActor *self = META_SURFACE_ACTOR (object); + MetaSurfaceActorPrivate *priv = self->priv; + + g_clear_pointer (&priv->input_region, cairo_region_destroy); + + G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object); +} + +static void +meta_surface_actor_class_init (MetaSurfaceActorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + + object_class->dispose = meta_surface_actor_dispose; + actor_class->pick = meta_surface_actor_pick; + + signals[REPAINT_SCHEDULED] = g_signal_new ("repaint-scheduled", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate)); +} + +static void +meta_surface_actor_cull_out (MetaCullable *cullable, + cairo_region_t *unobscured_region, + cairo_region_t *clip_region) +{ + meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); +} + +static void +meta_surface_actor_reset_culling (MetaCullable *cullable) +{ + meta_cullable_reset_culling_children (cullable); +} + +static void +cullable_iface_init (MetaCullableInterface *iface) +{ + iface->cull_out = meta_surface_actor_cull_out; + iface->reset_culling = meta_surface_actor_reset_culling; +} + +static void +meta_surface_actor_init (MetaSurfaceActor *self) +{ + MetaSurfaceActorPrivate *priv; + + priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + META_TYPE_SURFACE_ACTOR, + MetaSurfaceActorPrivate); + + priv->texture = META_SHAPED_TEXTURE (meta_shaped_texture_new ()); + clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->texture)); +} + +cairo_surface_t * +meta_surface_actor_get_image (MetaSurfaceActor *self, + cairo_rectangle_int_t *clip) +{ + return meta_shaped_texture_get_image (self->priv->texture, clip); +} + +MetaShapedTexture * +meta_surface_actor_get_texture (MetaSurfaceActor *self) +{ + return self->priv->texture; +} + +void +meta_surface_actor_update_area (MetaSurfaceActor *self, + int x, int y, int width, int height) +{ + MetaSurfaceActorPrivate *priv = self->priv; + + if (meta_shaped_texture_update_area (priv->texture, x, y, width, height)) + g_signal_emit (self, signals[REPAINT_SCHEDULED], 0); +} + +gboolean +meta_surface_actor_is_obscured (MetaSurfaceActor *self) +{ + MetaSurfaceActorPrivate *priv = self->priv; + return meta_shaped_texture_is_obscured (priv->texture); +} + +void +meta_surface_actor_set_input_region (MetaSurfaceActor *self, + cairo_region_t *region) +{ + MetaSurfaceActorPrivate *priv = self->priv; + + if (priv->input_region) + cairo_region_destroy (priv->input_region); + + if (region) + priv->input_region = cairo_region_reference (region); + else + priv->input_region = NULL; +} + +void +meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, + cairo_region_t *region) +{ + MetaSurfaceActorPrivate *priv = self->priv; + meta_shaped_texture_set_opaque_region (priv->texture, region); +} + +static gboolean +is_frozen (MetaSurfaceActor *self) +{ + MetaSurfaceActorPrivate *priv = self->priv; + return priv->frozen; +} + +void +meta_surface_actor_process_damage (MetaSurfaceActor *self, + int x, int y, int width, int height) +{ + MetaSurfaceActorPrivate *priv = self->priv; + + if (is_frozen (self)) + { + /* The window is frozen due to an effect in progress: we ignore damage + * here on the off chance that this will stop the corresponding + * texture_from_pixmap from being update. + * + * needs_damage_all tracks that some unknown damage happened while the + * window was frozen so that when the window becomes unfrozen we can + * issue a full window update to cover any lost damage. + * + * It should be noted that this is an unreliable mechanism since it's + * quite likely that drivers will aim to provide a zero-copy + * implementation of the texture_from_pixmap extension and in those cases + * any drawing done to the window is always immediately reflected in the + * texture regardless of damage event handling. + */ + priv->needs_damage_all = TRUE; + return; + } + + META_SURFACE_ACTOR_GET_CLASS (self)->process_damage (self, x, y, width, height); +} + +void +meta_surface_actor_pre_paint (MetaSurfaceActor *self) +{ + META_SURFACE_ACTOR_GET_CLASS (self)->pre_paint (self); +} + +gboolean +meta_surface_actor_is_argb32 (MetaSurfaceActor *self) +{ + MetaShapedTexture *stex = meta_surface_actor_get_texture (self); + CoglTexture *texture = meta_shaped_texture_get_texture (stex); + + /* If we don't have a texture, like during initialization, assume + * that we're ARGB32. */ + if (!texture) + return TRUE; + + switch (cogl_texture_get_components (texture)) + { + case COGL_TEXTURE_COMPONENTS_A: + case COGL_TEXTURE_COMPONENTS_RGBA: + return TRUE; + case COGL_TEXTURE_COMPONENTS_RG: + case COGL_TEXTURE_COMPONENTS_RGB: + case COGL_TEXTURE_COMPONENTS_DEPTH: + return FALSE; + default: + g_assert_not_reached (); + } +} + +gboolean +meta_surface_actor_is_visible (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->is_visible (self); +} + +void +meta_surface_actor_set_frozen (MetaSurfaceActor *self, + gboolean frozen) +{ + MetaSurfaceActorPrivate *priv = self->priv; + + priv->frozen = frozen; + + if (!frozen && priv->needs_damage_all) + { + /* Since we ignore damage events while a window is frozen for certain effects + * we may need to issue an update_area() covering the whole pixmap if we + * don't know what real damage has happened. */ + + meta_surface_actor_process_damage (self, 0, 0, + clutter_actor_get_width (CLUTTER_ACTOR (priv->texture)), + clutter_actor_get_height (CLUTTER_ACTOR (priv->texture))); + priv->needs_damage_all = FALSE; + } +} + +gboolean +meta_surface_actor_should_unredirect (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->should_unredirect (self); +} + +void +meta_surface_actor_set_unredirected (MetaSurfaceActor *self, + gboolean unredirected) +{ + META_SURFACE_ACTOR_GET_CLASS (self)->set_unredirected (self, unredirected); +} + +gboolean +meta_surface_actor_is_unredirected (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->is_unredirected (self); +} + +MetaWindow * +meta_surface_actor_get_window (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->get_window (self); +} diff --git a/src/compositor/meta-surface-actor.h b/src/compositor/meta-surface-actor.h new file mode 100644 index 0000000..3991d52 --- /dev/null +++ b/src/compositor/meta-surface-actor.h @@ -0,0 +1,85 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +#ifndef META_SURFACE_ACTOR_PRIVATE_H +#define META_SURFACE_ACTOR_PRIVATE_H + +#include <config.h> + +#include <meta/meta-shaped-texture.h> +#include <meta/window.h> + +G_BEGIN_DECLS + +#define META_TYPE_SURFACE_ACTOR (meta_surface_actor_get_type()) +#define META_SURFACE_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR, MetaSurfaceActor)) +#define META_SURFACE_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR, MetaSurfaceActorClass)) +#define META_IS_SURFACE_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR)) +#define META_IS_SURFACE_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR)) +#define META_SURFACE_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR, MetaSurfaceActorClass)) + +typedef struct _MetaSurfaceActor MetaSurfaceActor; +typedef struct _MetaSurfaceActorClass MetaSurfaceActorClass; +typedef struct _MetaSurfaceActorPrivate MetaSurfaceActorPrivate; + +struct _MetaSurfaceActorClass +{ + /*< private >*/ + ClutterActorClass parent_class; + + void (* process_damage) (MetaSurfaceActor *actor, + int x, int y, int width, int height); + void (* pre_paint) (MetaSurfaceActor *actor); + gboolean (* is_visible) (MetaSurfaceActor *actor); + + gboolean (* should_unredirect) (MetaSurfaceActor *actor); + void (* set_unredirected) (MetaSurfaceActor *actor, + gboolean unredirected); + gboolean (* is_unredirected) (MetaSurfaceActor *actor); + + MetaWindow *(* get_window) (MetaSurfaceActor *actor); +}; + +struct _MetaSurfaceActor +{ + ClutterActor parent; + + MetaSurfaceActorPrivate *priv; +}; + +GType meta_surface_actor_get_type (void); + +cairo_surface_t *meta_surface_actor_get_image (MetaSurfaceActor *self, + cairo_rectangle_int_t *clip); + +MetaShapedTexture *meta_surface_actor_get_texture (MetaSurfaceActor *self); +MetaWindow *meta_surface_actor_get_window (MetaSurfaceActor *self); + +gboolean meta_surface_actor_is_obscured (MetaSurfaceActor *self); +gboolean meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self, + cairo_rectangle_int_t *unobscured_bounds); + +void meta_surface_actor_set_input_region (MetaSurfaceActor *self, + cairo_region_t *region); +void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, + cairo_region_t *region); + +void meta_surface_actor_update_area (MetaSurfaceActor *actor, + int x, int y, int width, int height); + +void meta_surface_actor_process_damage (MetaSurfaceActor *actor, + int x, int y, int width, int height); +void meta_surface_actor_pre_paint (MetaSurfaceActor *actor); +gboolean meta_surface_actor_is_argb32 (MetaSurfaceActor *actor); +gboolean meta_surface_actor_is_visible (MetaSurfaceActor *actor); + +void meta_surface_actor_set_frozen (MetaSurfaceActor *actor, + gboolean frozen); + +gboolean meta_surface_actor_should_unredirect (MetaSurfaceActor *actor); +void meta_surface_actor_set_unredirected (MetaSurfaceActor *actor, + gboolean unredirected); +gboolean meta_surface_actor_is_unredirected (MetaSurfaceActor *actor); + +G_END_DECLS + +#endif /* META_SURFACE_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h index 75a19e1..2d27850 100644 --- a/src/compositor/meta-window-actor-private.h +++ b/src/compositor/meta-window-actor-private.h @@ -7,6 +7,7 @@ #include <X11/extensions/Xdamage.h> #include <meta/compositor-mutter.h> +#include "meta-surface-actor.h" MetaWindowActor *meta_window_actor_new (MetaWindow *window); @@ -24,8 +25,8 @@ void meta_window_actor_unmaximize (MetaWindowActor *self, MetaRectangle *old_rect, MetaRectangle *new_rect); -void meta_window_actor_process_damage (MetaWindowActor *self, - XDamageNotifyEvent *event); +void meta_window_actor_process_x11_damage (MetaWindowActor *self, + XDamageNotifyEvent *event); void meta_window_actor_pre_paint (MetaWindowActor *self); void meta_window_actor_post_paint (MetaWindowActor *self); @@ -58,4 +59,7 @@ void meta_window_actor_queue_frame_drawn (MetaWindowActor *self, void meta_window_actor_effect_completed (MetaWindowActor *actor, gulong event); +MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self); +void meta_window_actor_update_surface (MetaWindowActor *self); + #endif /* META_WINDOW_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index b63358f..ae5a276 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -10,10 +10,6 @@ #include <math.h> -#include <X11/extensions/Xcomposite.h> -#include <X11/extensions/Xdamage.h> -#include <X11/extensions/Xrender.h> - #include <clutter/x11/clutter-x11.h> #include <cogl/cogl-texture-pixmap-x11.h> #include <gdk/gdk.h> /* for gdk_rectangle_union() */ @@ -24,7 +20,6 @@ #include "frame.h" #include <meta/window.h> #include <meta/meta-shaped-texture.h> -#include "xprops.h" #include "compositor-private.h" #include "meta-shaped-texture-private.h" @@ -32,15 +27,20 @@ #include "meta-window-actor-private.h" #include "meta-texture-rectangle.h" #include "region-utils.h" -#include "monitor-private.h" +#include "meta-monitor-manager.h" #include "meta-cullable.h" +#include "meta-surface-actor.h" +#include "meta-surface-actor-x11.h" + +#include "wayland/meta-wayland-surface.h" + struct _MetaWindowActorPrivate { - MetaWindow *window; - MetaScreen *screen; + MetaWindow *window; + MetaCompositor *compositor; - ClutterActor *actor; + MetaSurfaceActor *surface; /* MetaShadowFactory only caches shadows that are actually in use; * to avoid unnecessary recomputation we do two things: 1) we store @@ -56,10 +56,6 @@ struct _MetaWindowActorPrivate MetaShadow *focused_shadow; MetaShadow *unfocused_shadow; - Pixmap back_pixmap; - - Damage damage; - /* A region that matches the shape of the window, including frame bounds */ cairo_region_t *shape_region; /* The region we should clip to when painting the shadow */ @@ -72,10 +68,8 @@ struct _MetaWindowActorPrivate guint send_frame_messages_timer; gint64 frame_drawn_time; - gint last_width; - gint last_height; - - gint freeze_count; + guint repaint_scheduled_id; + guint allocation_changed_id; /* * These need to be counters rather than flags, since more plugins @@ -90,36 +84,25 @@ struct _MetaWindowActorPrivate /* List of FrameData for recent frames */ GList *frames; + guint freeze_count; guint visible : 1; - guint argb32 : 1; guint disposed : 1; - guint redecorating : 1; - - guint needs_damage_all : 1; - guint received_damage : 1; - guint repaint_scheduled : 1; /* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN * client message using the most recent frame in ->frames */ guint needs_frame_drawn : 1; + guint repaint_scheduled : 1; - guint needs_pixmap : 1; guint needs_reshape : 1; guint recompute_focused_shadow : 1; guint recompute_unfocused_shadow : 1; - guint size_changed : 1; - guint updates_frozen : 1; guint needs_destroy : 1; guint no_shadow : 1; - guint unredirected : 1; - - /* This is used to detect fullscreen windows that need to be unredirected */ - guint full_damage_frames_count; - guint does_full_damage : 1; + guint updates_frozen : 1; }; typedef struct _FrameData FrameData; @@ -156,7 +139,6 @@ static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume); -static void meta_window_actor_detach (MetaWindowActor *self); static gboolean meta_window_actor_has_shadow (MetaWindowActor *self); static void meta_window_actor_handle_updates (MetaWindowActor *self); @@ -241,48 +223,46 @@ meta_window_actor_init (MetaWindowActor *self) } static void -window_decorated_notify (MetaWindow *mw, - GParamSpec *arg1, - gpointer data) +window_appears_focused_notify (MetaWindow *mw, + GParamSpec *arg1, + gpointer data) { - MetaWindowActor *self = META_WINDOW_ACTOR (data); - MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - - /* - * Basically, we have to reconstruct the the internals of this object - * from scratch, as everything has changed. - */ - priv->redecorating = TRUE; + clutter_actor_queue_redraw (CLUTTER_ACTOR (data)); +} - meta_window_actor_detach (self); +static void +surface_allocation_changed_notify (ClutterActor *actor, + const ClutterActorBox *allocation, + ClutterAllocationFlags flags, + MetaWindowActor *self) +{ + meta_window_actor_sync_actor_geometry (self, FALSE); + meta_window_actor_update_shape (self); +} - /* - * First of all, clean up any resources we are currently using and will - * be replacing. - */ - if (priv->damage != None) - { - meta_error_trap_push (display); - XDamageDestroy (xdisplay, priv->damage); - meta_error_trap_pop (display); - priv->damage = None; - } +static void +surface_repaint_scheduled (MetaSurfaceActor *actor, + gpointer user_data) +{ + MetaWindowActor *self = META_WINDOW_ACTOR (user_data); + MetaWindowActorPrivate *priv = self->priv; - /* - * Recreate the contents. - */ - meta_window_actor_constructed (G_OBJECT (self)); + priv->repaint_scheduled = TRUE; } -static void -window_appears_focused_notify (MetaWindow *mw, - GParamSpec *arg1, - gpointer data) +static gboolean +is_argb32 (MetaWindowActor *self) { - clutter_actor_queue_redraw (CLUTTER_ACTOR (data)); + MetaWindowActorPrivate *priv = self->priv; + + /* assume we're argb until we get the window (because + in practice we're drawing nothing, so we're fully + transparent) + */ + if (priv->surface) + return meta_surface_actor_is_argb32 (priv->surface); + else + return TRUE; } static gboolean @@ -291,47 +271,113 @@ is_non_opaque (MetaWindowActor *self) MetaWindowActorPrivate *priv = self->priv; MetaWindow *window = priv->window; - return priv->argb32 || (window->opacity != 0xFF); + return is_argb32 (self) || (window->opacity != 0xFF); +} + +static gboolean +is_frozen (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + return priv->surface == NULL || priv->freeze_count > 0; } static void -meta_window_actor_constructed (GObject *object) +meta_window_actor_freeze (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + if (priv->freeze_count == 0 && priv->surface) + meta_surface_actor_set_frozen (priv->surface, TRUE); + + priv->freeze_count ++; +} + +static void +meta_window_actor_thaw (MetaWindowActor *self) { - MetaWindowActor *self = META_WINDOW_ACTOR (object); - MetaWindowActorPrivate *priv = self->priv; - MetaWindow *window = priv->window; - MetaScreen *screen = meta_window_get_screen (window); - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - XRenderPictFormat *format; - Window xwindow; + MetaWindowActorPrivate *priv = self->priv; - xwindow = meta_window_get_toplevel_xwindow (window); + if (priv->freeze_count <= 0) + g_error ("Error in freeze/thaw accounting"); - priv->screen = screen; - priv->damage = XDamageCreate (xdisplay, xwindow, - XDamageReportBoundingBox); + priv->freeze_count--; + if (priv->freeze_count > 0) + return; - format = XRenderFindVisualFormat (xdisplay, window->xvisual); + if (priv->surface) + meta_surface_actor_set_frozen (priv->surface, FALSE); - if (format && format->type == PictTypeDirect && format->direct.alphaMask) - priv->argb32 = TRUE; + /* We sometimes ignore moves and resizes on frozen windows */ + meta_window_actor_sync_actor_geometry (self, FALSE); - if (!priv->actor) + /* We do this now since we might be going right back into the + * frozen state */ + meta_window_actor_handle_updates (self); +} + +static void +set_surface (MetaWindowActor *self, + MetaSurfaceActor *surface) +{ + MetaWindowActorPrivate *priv = self->priv; + + if (priv->surface) { - priv->actor = meta_shaped_texture_new (); + g_signal_handler_disconnect (priv->surface, priv->repaint_scheduled_id); + priv->repaint_scheduled_id = 0; + g_signal_handler_disconnect (priv->surface, priv->allocation_changed_id); + priv->allocation_changed_id = 0; + clutter_actor_remove_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface)); + g_object_unref (priv->surface); + } - clutter_actor_add_child (CLUTTER_ACTOR (self), priv->actor); + priv->surface = surface; - /* - * Since we are holding a pointer to this actor independently of the - * ClutterContainer internals, and provide a public API to access it, - * add a reference here, so that if someone is messing about with us - * via the container interface, we do not end up with a dangling pointer. - * We will release it in dispose(). - */ - g_object_ref (priv->actor); + if (priv->surface) + { + g_object_ref_sink (priv->surface); + priv->repaint_scheduled_id = g_signal_connect (priv->surface, "repaint-scheduled", + G_CALLBACK (surface_repaint_scheduled), self); + priv->allocation_changed_id = g_signal_connect (priv->surface, "allocation-changed", + G_CALLBACK (surface_allocation_changed_notify), self); + clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface)); + + /* If the previous surface actor was frozen, start out + * frozen as well... */ + meta_surface_actor_set_frozen (priv->surface, priv->freeze_count > 0); + + meta_window_actor_update_shape (self); } +} + +void +meta_window_actor_update_surface (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + MetaWindow *window = priv->window; + MetaSurfaceActor *surface_actor; + + if (window->surface) + surface_actor = window->surface->surface_actor; + else if (!meta_is_wayland_compositor ()) + surface_actor = meta_surface_actor_x11_new (window); + else + surface_actor = NULL; + + set_surface (self, surface_actor); +} + +static void +meta_window_actor_constructed (GObject *object) +{ + MetaWindowActor *self = META_WINDOW_ACTOR (object); + MetaWindowActorPrivate *priv = self->priv; + MetaWindow *window = priv->window; + + priv->compositor = window->display->compositor; + + meta_window_actor_update_surface (self); meta_window_actor_update_opacity (self); @@ -343,25 +389,15 @@ meta_window_actor_constructed (GObject *object) static void meta_window_actor_dispose (GObject *object) { - MetaWindowActor *self = META_WINDOW_ACTOR (object); + MetaWindowActor *self = META_WINDOW_ACTOR (object); MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen; - MetaDisplay *display; - Display *xdisplay; - MetaCompScreen *info; + MetaCompositor *compositor = priv->compositor; if (priv->disposed) return; priv->disposed = TRUE; - screen = priv->screen; - display = meta_screen_get_display (screen); - xdisplay = meta_display_get_xdisplay (display); - info = meta_screen_get_compositor_data (screen); - - meta_window_actor_detach (self); - if (priv->send_frame_messages_timer != 0) { g_source_remove (priv->send_frame_messages_timer); @@ -376,23 +412,11 @@ meta_window_actor_dispose (GObject *object) g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref); g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref); - if (priv->damage != None) - { - meta_error_trap_push (display); - XDamageDestroy (xdisplay, priv->damage); - meta_error_trap_pop (display); - - priv->damage = None; - } - - info->windows = g_list_remove (info->windows, (gconstpointer) self); + compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self); g_clear_object (&priv->window); - /* - * Release the extra reference we took on the actor. - */ - g_clear_object (&priv->actor); + set_surface (self, NULL); G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object); } @@ -421,9 +445,6 @@ meta_window_actor_set_property (GObject *object, { case PROP_META_WINDOW: priv->window = g_value_dup_object (value); - - g_signal_connect_object (priv->window, "notify::decorated", - G_CALLBACK (window_decorated_notify), self, 0); g_signal_connect_object (priv->window, "notify::appears-focused", G_CALLBACK (window_appears_focused_notify), self, 0); break; @@ -645,8 +666,11 @@ meta_window_actor_get_paint_volume (ClutterActor *actor, meta_window_actor_get_shape_bounds (self, &bounds); - if (meta_shaped_texture_get_unobscured_bounds (META_SHAPED_TEXTURE (priv->actor), &unobscured_bounds)) - gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds); + if (priv->surface) + { + if (meta_surface_actor_get_unobscured_bounds (priv->surface, &unobscured_bounds)) + gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds); + } if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow) { @@ -678,7 +702,6 @@ static gboolean meta_window_actor_has_shadow (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - MetaWindowType window_type = meta_window_get_window_type (priv->window); if (priv->no_shadow) return FALSE; @@ -717,25 +740,6 @@ meta_window_actor_has_shadow (MetaWindowActor *self) if (priv->window->override_redirect) return TRUE; - /* - * Don't put shadow around DND icon windows - */ - if (window_type == META_WINDOW_DND || - window_type == META_WINDOW_DESKTOP) - return FALSE; - - if (window_type == META_WINDOW_MENU -#if 0 - || window_type == META_WINDOW_DROPDOWN_MENU -#endif - ) - return TRUE; - -#if 0 - if (window_type == META_WINDOW_TOOLTIP) - return TRUE; -#endif - return FALSE; } @@ -757,14 +761,33 @@ meta_window_actor_get_meta_window (MetaWindowActor *self) * meta_window_actor_get_texture: * @self: a #MetaWindowActor * - * Gets the ClutterActor that is used to display the contents of the window + * Gets the ClutterActor that is used to display the contents of the window, + * or NULL if no texture is shown yet, because the window is not mapped. * * Return value: (transfer none): the #ClutterActor for the contents */ ClutterActor * meta_window_actor_get_texture (MetaWindowActor *self) { - return self->priv->actor; + if (self->priv->surface) + return CLUTTER_ACTOR (meta_surface_actor_get_texture (self->priv->surface)); + else + return NULL; +} + +/** + * meta_window_actor_get_surface: + * @self: a #MetaWindowActor + * + * Gets the MetaSurfaceActor that draws the content of this window, + * or NULL if there is no surface yet associated with this window. + * + * Return value: (transfer none): the #MetaSurfaceActor for the contents + */ +MetaSurfaceActor * +meta_window_actor_get_surface (MetaWindowActor *self) +{ + return self->priv->surface; } /** @@ -781,14 +804,8 @@ meta_window_actor_is_destroyed (MetaWindowActor *self) return self->priv->disposed; } -static void -meta_window_actor_freeze (MetaWindowActor *self) -{ - self->priv->freeze_count++; -} - -static -gboolean send_frame_messages_timeout (gpointer data) +static gboolean +send_frame_messages_timeout (gpointer data) { MetaWindowActor *self = (MetaWindowActor *) data; MetaWindowActorPrivate *priv = self->priv; @@ -810,8 +827,7 @@ static void queue_send_frame_messages_timeout (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); + MetaDisplay *display = meta_window_get_display (priv->window); gint64 current_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ()); MetaMonitorManager *monitor_manager = meta_monitor_manager_get (); MetaWindow *window = priv->window; @@ -841,72 +857,6 @@ queue_send_frame_messages_timeout (MetaWindowActor *self) priv->send_frame_messages_timer = g_timeout_add_full (META_PRIORITY_REDRAW, offset, send_frame_messages_timeout, self, NULL); } -static void -update_area (MetaWindowActor *self, - int x, int y, int width, int height) -{ - MetaWindowActorPrivate *priv = self->priv; - CoglTexture *texture; - - texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor)); - - cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (texture), - x, y, width, height); -} - -static void -meta_window_actor_damage_all (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - CoglTexture *texture; - gboolean redraw_queued; - - if (!priv->needs_damage_all) - return; - - texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor)); - - if (priv->needs_pixmap) - return; - - update_area (self, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture)); - redraw_queued = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor), - 0, 0, - cogl_texture_get_width (texture), - cogl_texture_get_height (texture)); - priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued; - priv->needs_damage_all = FALSE; -} - -static void -meta_window_actor_thaw (MetaWindowActor *self) -{ - self->priv->freeze_count--; - - if (G_UNLIKELY (self->priv->freeze_count < 0)) - { - g_warning ("Error in freeze/thaw accounting."); - self->priv->freeze_count = 0; - return; - } - - if (self->priv->freeze_count) - return; - - /* We sometimes ignore moves and resizes on frozen windows */ - meta_window_actor_sync_actor_geometry (self, FALSE); - - /* We do this now since we might be going right back into the - * frozen state */ - meta_window_actor_handle_updates (self); - - /* Since we ignore damage events while a window is frozen for certain effects - * we may need to issue an update_area() covering the whole pixmap if we - * don't know what real damage has happened. */ - if (self->priv->needs_damage_all) - meta_window_actor_damage_all (self); -} - void meta_window_actor_queue_frame_drawn (MetaWindowActor *self, gboolean no_delay_frame) @@ -928,7 +878,12 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self, if (!priv->repaint_scheduled) { - gboolean is_obscured = meta_shaped_texture_is_obscured (META_SHAPED_TEXTURE (priv->actor)); + gboolean is_obscured; + + if (priv->surface) + is_obscured = meta_surface_actor_is_obscured (priv->surface); + else + is_obscured = FALSE; /* A frame was marked by the client without actually doing any * damage or any unobscured, or while we had the window frozen @@ -944,9 +899,12 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self, } else { - const cairo_rectangle_int_t clip = { 0, 0, 1, 1 }; - clutter_actor_queue_redraw_with_clip (priv->actor, &clip); - priv->repaint_scheduled = TRUE; + if (priv->surface) + { + const cairo_rectangle_int_t clip = { 0, 0, 1, 1 }; + clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (priv->surface), &clip); + priv->repaint_scheduled = TRUE; + } } } } @@ -962,12 +920,6 @@ meta_window_actor_effect_in_progress (MetaWindowActor *self) } static gboolean -is_frozen (MetaWindowActor *self) -{ - return self->priv->freeze_count ? TRUE : FALSE; -} - -static gboolean is_freeze_thaw_effect (gulong event) { switch (event) @@ -987,13 +939,10 @@ start_simple_effect (MetaWindowActor *self, gulong event) { MetaWindowActorPrivate *priv = self->priv; - MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen); + MetaCompositor *compositor = priv->compositor; gint *counter = NULL; gboolean use_freeze_thaw = FALSE; - if (!info->plugin_mgr) - return FALSE; - switch (event) { case META_PLUGIN_MINIMIZE: @@ -1021,9 +970,7 @@ start_simple_effect (MetaWindowActor *self, (*counter)++; - if (!meta_plugin_manager_event_simple (info->plugin_mgr, - self, - event)) + if (!meta_plugin_manager_event_simple (compositor->plugin_mgr, self, event)) { (*counter)--; if (use_freeze_thaw) @@ -1047,9 +994,6 @@ meta_window_actor_after_effects (MetaWindowActor *self) meta_window_actor_sync_visibility (self); meta_window_actor_sync_actor_geometry (self, FALSE); - - if (priv->needs_pixmap) - clutter_actor_queue_redraw (priv->actor); } void @@ -1124,106 +1068,34 @@ meta_window_actor_effect_completed (MetaWindowActor *self, meta_window_actor_after_effects (self); } -/* Called to drop our reference to a window backing pixmap that we - * previously obtained with XCompositeNameWindowPixmap. We do this - * when the window is unmapped or when we want to update to a new - * pixmap for a new size. - */ -static void -meta_window_actor_detach (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - - if (!priv->back_pixmap) - return; - - /* Get rid of all references to the pixmap before freeing it; it's unclear whether - * you are supposed to be able to free a GLXPixmap after freeing the underlying - * pixmap, but it certainly doesn't work with current DRI/Mesa - */ - meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), NULL); - cogl_flush(); - - XFreePixmap (xdisplay, priv->back_pixmap); - priv->back_pixmap = None; - - priv->needs_pixmap = TRUE; -} - gboolean meta_window_actor_should_unredirect (MetaWindowActor *self) { - MetaWindow *metaWindow = meta_window_actor_get_meta_window (self); MetaWindowActorPrivate *priv = self->priv; - - if (meta_window_requested_dont_bypass_compositor (metaWindow)) - return FALSE; - - if (metaWindow->opacity != 0xFF) - return FALSE; - - if (metaWindow->shape_region != NULL) - return FALSE; - - if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow)) - return FALSE; - - if (!meta_window_is_monitor_sized (metaWindow)) + if (priv->surface) + return meta_surface_actor_should_unredirect (priv->surface); + else return FALSE; - - if (meta_window_requested_bypass_compositor (metaWindow)) - return TRUE; - - if (meta_window_is_override_redirect (metaWindow)) - return TRUE; - - if (priv->does_full_damage) - return TRUE; - - return FALSE; } void meta_window_actor_set_unredirected (MetaWindowActor *self, gboolean unredirected) { - MetaWindow *metaWindow = meta_window_actor_get_meta_window (self); - MetaDisplay *display = meta_window_get_display (metaWindow); - - Display *xdisplay = meta_display_get_xdisplay (display); - Window xwin = meta_window_get_toplevel_xwindow (metaWindow); - - meta_error_trap_push (display); - - if (unredirected) - { - XCompositeUnredirectWindow (xdisplay, xwin, CompositeRedirectManual); - } - else - { - XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual); - meta_window_actor_detach (self); - } + MetaWindowActorPrivate *priv = self->priv; - self->priv->unredirected = unredirected; - meta_error_trap_pop (display); + g_assert(priv->surface); /* because otherwise should_unredirect() is FALSE */ + meta_surface_actor_set_unredirected (priv->surface, unredirected); } void meta_window_actor_destroy (MetaWindowActor *self) { - MetaWindow *window; - MetaCompScreen *info; - MetaWindowActorPrivate *priv; - MetaWindowType window_type; - - priv = self->priv; + MetaWindowActorPrivate *priv = self->priv; + MetaWindow *window = priv->window; + MetaCompositor *compositor = priv->compositor; + MetaWindowType window_type = meta_window_get_window_type (window); - window = priv->window; - window_type = meta_window_get_window_type (window); meta_window_set_compositor_private (window, NULL); if (priv->send_frame_messages_timer != 0) @@ -1236,8 +1108,7 @@ meta_window_actor_destroy (MetaWindowActor *self) * We remove the window from internal lookup hashes and thus any other * unmap events etc fail */ - info = meta_screen_get_compositor_data (priv->screen); - info->windows = g_list_remove (info->windows, (gconstpointer) self); + compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self); if (window_type == META_WINDOW_DROPDOWN_MENU || window_type == META_WINDOW_POPUP_MENU || @@ -1269,13 +1140,11 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self, meta_window_get_input_rect (priv->window, &window_rect); - if (priv->last_width != window_rect.width || - priv->last_height != window_rect.height) - { - priv->size_changed = TRUE; - priv->last_width = window_rect.width; - priv->last_height = window_rect.height; - } + /* When running as a Wayland compositor we catch size changes when new + * buffers are attached */ + if (META_IS_SURFACE_ACTOR_X11 (priv->surface)) + meta_surface_actor_x11_set_size (META_SURFACE_ACTOR_X11 (priv->surface), + window_rect.width, window_rect.height); /* Normally we want freezing a window to also freeze its position; this allows * windows to atomically move and resize together, either under app control, @@ -1287,12 +1156,6 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self, if (is_frozen (self) && !did_placement) return; - if (priv->size_changed) - { - priv->needs_pixmap = TRUE; - meta_window_actor_update_shape (self); - } - if (meta_window_actor_effect_in_progress (self)) return; @@ -1306,18 +1169,14 @@ void meta_window_actor_show (MetaWindowActor *self, MetaCompEffect effect) { - MetaWindowActorPrivate *priv; - MetaCompScreen *info; - gulong event; - - priv = self->priv; - info = meta_screen_get_compositor_data (priv->screen); + MetaWindowActorPrivate *priv = self->priv; + MetaCompositor *compositor = priv->compositor; + gulong event = 0; g_return_if_fail (!priv->visible); self->priv->visible = TRUE; - event = 0; switch (effect) { case META_COMP_EFFECT_CREATE: @@ -1334,13 +1193,11 @@ meta_window_actor_show (MetaWindowActor *self, g_assert_not_reached(); } - if (priv->redecorating || - info->switch_workspace_in_progress || + if (compositor->switch_workspace_in_progress || event == 0 || !start_simple_effect (self, event)) { clutter_actor_show (CLUTTER_ACTOR (self)); - priv->redecorating = FALSE; } } @@ -1348,12 +1205,9 @@ void meta_window_actor_hide (MetaWindowActor *self, MetaCompEffect effect) { - MetaWindowActorPrivate *priv; - MetaCompScreen *info; - gulong event; - - priv = self->priv; - info = meta_screen_get_compositor_data (priv->screen); + MetaWindowActorPrivate *priv = self->priv; + MetaCompositor *compositor = priv->compositor; + gulong event = 0; g_return_if_fail (priv->visible); @@ -1363,10 +1217,9 @@ meta_window_actor_hide (MetaWindowActor *self, * hold off on hiding the window, and do it after the workspace * switch completes */ - if (info->switch_workspace_in_progress) + if (compositor->switch_workspace_in_progress) return; - event = 0; switch (effect) { case META_COMP_EFFECT_DESTROY: @@ -1392,7 +1245,8 @@ meta_window_actor_maximize (MetaWindowActor *self, MetaRectangle *old_rect, MetaRectangle *new_rect) { - MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen); + MetaWindowActorPrivate *priv = self->priv; + MetaCompositor *compositor = priv->compositor; /* The window has already been resized (in order to compute new_rect), * which by side effect caused the actor to be resized. Restore it to the @@ -1403,8 +1257,7 @@ meta_window_actor_maximize (MetaWindowActor *self, self->priv->maximize_in_progress++; meta_window_actor_freeze (self); - if (!info->plugin_mgr || - !meta_plugin_manager_event_maximize (info->plugin_mgr, + if (!meta_plugin_manager_event_maximize (compositor->plugin_mgr, self, META_PLUGIN_MAXIMIZE, new_rect->x, new_rect->y, @@ -1421,7 +1274,8 @@ meta_window_actor_unmaximize (MetaWindowActor *self, MetaRectangle *old_rect, MetaRectangle *new_rect) { - MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen); + MetaWindowActorPrivate *priv = self->priv; + MetaCompositor *compositor = priv->compositor; /* The window has already been resized (in order to compute new_rect), * which by side effect caused the actor to be resized. Restore it to the @@ -1432,8 +1286,7 @@ meta_window_actor_unmaximize (MetaWindowActor *self, self->priv->unmaximize_in_progress++; meta_window_actor_freeze (self); - if (!info->plugin_mgr || - !meta_plugin_manager_event_maximize (info->plugin_mgr, + if (!meta_plugin_manager_event_maximize (compositor->plugin_mgr, self, META_PLUGIN_UNMAXIMIZE, new_rect->x, new_rect->y, @@ -1447,8 +1300,8 @@ meta_window_actor_unmaximize (MetaWindowActor *self, MetaWindowActor * meta_window_actor_new (MetaWindow *window) { - MetaScreen *screen = meta_window_get_screen (window); - MetaCompScreen *info = meta_screen_get_compositor_data (screen); + MetaDisplay *display = meta_window_get_display (window); + MetaCompositor *compositor = display->compositor; MetaWindowActor *self; MetaWindowActorPrivate *priv; ClutterActor *window_group; @@ -1459,13 +1312,7 @@ meta_window_actor_new (MetaWindow *window) priv = self->priv; - priv->last_width = -1; - priv->last_height = -1; - - priv->needs_pixmap = TRUE; - - meta_window_actor_set_updates_frozen (self, - meta_window_updates_are_frozen (priv->window)); + meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (priv->window)); /* If a window doesn't start off with updates frozen, we should * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn. @@ -1479,20 +1326,18 @@ meta_window_actor_new (MetaWindow *window) meta_window_set_compositor_private (window, G_OBJECT (self)); if (window->layer == META_LAYER_OVERRIDE_REDIRECT) - window_group = info->top_window_group; + window_group = compositor->top_window_group; else - window_group = info->window_group; + window_group = compositor->window_group; clutter_actor_add_child (window_group, CLUTTER_ACTOR (self)); clutter_actor_hide (CLUTTER_ACTOR (self)); - clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE); - /* Initial position in the stack is arbitrary; stacking will be synced * before we first paint. */ - info->windows = g_list_append (info->windows, self); + compositor->windows = g_list_append (compositor->windows, self); return self; } @@ -1582,11 +1427,6 @@ meta_window_actor_cull_out (MetaCullable *cullable, cairo_region_t *clip_region) { MetaWindowActor *self = META_WINDOW_ACTOR (cullable); - MetaWindowActorPrivate *priv = self->priv; - - /* Don't do any culling for the unredirected window */ - if (priv->unredirected) - return; meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); meta_window_actor_set_clip_region_beneath (self, clip_region); @@ -1599,6 +1439,7 @@ meta_window_actor_reset_culling (MetaCullable *cullable) MetaWindowActorPrivate *priv = self->priv; g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); + meta_cullable_reset_culling_children (cullable); } @@ -1610,78 +1451,6 @@ cullable_iface_init (MetaCullableInterface *iface) } static void -check_needs_pixmap (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - Window xwindow = meta_window_get_toplevel_xwindow (priv->window); - MetaCompositor *compositor; - - if (!priv->needs_pixmap) - return; - - if (xwindow == meta_screen_get_xroot (screen) || - xwindow == clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage))) - return; - - compositor = meta_display_get_compositor (display); - - if (priv->size_changed) - { - meta_window_actor_detach (self); - priv->size_changed = FALSE; - } - - meta_error_trap_push (display); - - if (priv->back_pixmap == None) - { - CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - CoglTexture *texture; - - meta_error_trap_push (display); - - priv->back_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow); - - if (meta_error_trap_pop_with_return (display) != Success) - { - /* Probably a BadMatch if the window isn't viewable; we could - * GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync - * to avoid this, but there's no reason to take two round trips - * when one will do. (We need that Sync if we want to handle failures - * for any reason other than !viewable. That's unlikely, but maybe - * we'll BadAlloc or something.) - */ - priv->back_pixmap = None; - } - - if (priv->back_pixmap == None) - { - meta_verbose ("Unable to get named pixmap for %p\n", self); - goto out; - } - - if (compositor->no_mipmaps) - meta_shaped_texture_set_create_mipmaps (META_SHAPED_TEXTURE (priv->actor), - FALSE); - - texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL)); - if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture)))) - g_warning ("NOTE: Not using GLX TFP!\n"); - - meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), texture); - } - - priv->needs_pixmap = FALSE; - - out: - meta_error_trap_pop (display); -} - -static void check_needs_shadow (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; @@ -1744,66 +1513,17 @@ check_needs_shadow (MetaWindowActor *self) } void -meta_window_actor_process_damage (MetaWindowActor *self, - XDamageNotifyEvent *event) +meta_window_actor_process_x11_damage (MetaWindowActor *self, + XDamageNotifyEvent *event) { MetaWindowActorPrivate *priv = self->priv; - MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen); - gboolean redraw_queued; - priv->received_damage = TRUE; - - if (meta_window_is_fullscreen (priv->window) && g_list_last (info->windows)->data == self && !priv->unredirected) - { - MetaRectangle window_rect; - meta_window_get_frame_rect (priv->window, &window_rect); - - if (window_rect.x == event->area.x && - window_rect.y == event->area.y && - window_rect.width == event->area.width && - window_rect.height == event->area.height) - priv->full_damage_frames_count++; - else - priv->full_damage_frames_count = 0; - - if (priv->full_damage_frames_count >= 100) - priv->does_full_damage = TRUE; - } - - /* Drop damage event for unredirected windows */ - if (priv->unredirected) - return; - - if (is_frozen (self)) - { - /* The window is frozen due to an effect in progress: we ignore damage - * here on the off chance that this will stop the corresponding - * texture_from_pixmap from being update. - * - * needs_damage_all tracks that some unknown damage happened while the - * window was frozen so that when the window becomes unfrozen we can - * issue a full window update to cover any lost damage. - * - * It should be noted that this is an unreliable mechanism since it's - * quite likely that drivers will aim to provide a zero-copy - * implementation of the texture_from_pixmap extension and in those cases - * any drawing done to the window is always immediately reflected in the - * texture regardless of damage event handling. - */ - priv->needs_damage_all = TRUE; - return; - } - - if (priv->needs_pixmap) - return; - - update_area (self, event->area.x, event->area.y, event->area.width, event->area.height); - redraw_queued = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor), - event->area.x, - event->area.y, - event->area.width, - event->area.height); - priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued; + if (priv->surface) + meta_surface_actor_process_damage (priv->surface, + event->area.x, + event->area.y, + event->area.width, + event->area.height); } void @@ -1865,12 +1585,18 @@ build_and_scan_frame_mask (MetaWindowActor *self, MetaWindowActorPrivate *priv = self->priv; guchar *mask_data; guint tex_width, tex_height; + MetaShapedTexture *stex; CoglTexture *paint_tex, *mask_texture; int stride; cairo_t *cr; cairo_surface_t *surface; - paint_tex = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor)); + stex = meta_surface_actor_get_texture (priv->surface); + g_return_if_fail (stex); + + meta_shaped_texture_set_mask_texture (stex, NULL); + + paint_tex = meta_shaped_texture_get_texture (stex); if (paint_tex == NULL) return; @@ -1944,8 +1670,7 @@ build_and_scan_frame_mask (MetaWindowActor *self, mask_data); } - meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), - mask_texture); + meta_shaped_texture_set_mask_texture (stex, mask_texture); if (mask_texture) cogl_object_unref (mask_texture); @@ -1978,7 +1703,6 @@ meta_window_actor_update_shape_region (MetaWindowActor *self) region = cairo_region_create_rectangle (&client_area); } - meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL); if ((priv->window->shape_region != NULL) || (priv->window->frame != NULL)) build_and_scan_frame_mask (self, &client_area, region); @@ -1994,44 +1718,22 @@ static void meta_window_actor_update_input_region (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor); - cairo_region_t *region = NULL; - cairo_rectangle_int_t client_area; - - meta_window_get_client_area_rect (priv->window, &client_area); - - if (priv->window->frame != NULL) - { - region = meta_frame_get_frame_bounds (priv->window->frame); + MetaWindow *window = priv->window; + cairo_region_t *region; - /* client area is in client window coordinates, so translate the - * input region into that coordinate system and back */ - cairo_region_translate (region, -client_area.x, -client_area.y); - cairo_region_union_rectangle (region, &client_area); - cairo_region_translate (region, client_area.x, client_area.y); - } - else if (priv->window->shape_region != NULL || - priv->window->input_region != NULL) + if (window->shape_region && window->input_region) { - if (priv->window->shape_region != NULL) - { - region = cairo_region_copy (priv->window->shape_region); - - if (priv->window->input_region != NULL) - cairo_region_intersect (region, priv->window->input_region); - } - else - region = cairo_region_reference (priv->window->input_region); + region = cairo_region_copy (window->shape_region); + cairo_region_intersect (region, window->input_region); } + else if (window->shape_region) + region = cairo_region_reference (window->shape_region); + else if (window->input_region) + region = cairo_region_reference (window->input_region); else - { - /* If we don't have a shape on the server, that means that - * we have an implicit shape of one rectangle covering the - * entire window. */ - region = cairo_region_create_rectangle (&client_area); - } + region = NULL; - meta_shaped_texture_set_input_shape_region (stex, region); + meta_surface_actor_set_input_region (priv->surface, region); cairo_region_destroy (region); } @@ -2040,8 +1742,9 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; cairo_region_t *opaque_region; + gboolean argb32 = is_argb32 (self); - if (priv->argb32 && priv->window->opaque_region != NULL) + if (argb32 && priv->window->opaque_region != NULL) { cairo_rectangle_int_t client_area; @@ -2061,12 +1764,12 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self) cairo_region_translate (opaque_region, client_area.x, client_area.y); cairo_region_intersect (opaque_region, priv->shape_region); } - else if (priv->argb32) + else if (argb32) opaque_region = NULL; else opaque_region = cairo_region_reference (priv->shape_region); - meta_shaped_texture_set_opaque_region (META_SHAPED_TEXTURE (priv->actor), opaque_region); + meta_surface_actor_set_opaque_region (priv->surface, opaque_region); cairo_region_destroy (opaque_region); } @@ -2079,8 +1782,12 @@ check_needs_reshape (MetaWindowActor *self) return; meta_window_actor_update_shape_region (self); - meta_window_actor_update_input_region (self); - meta_window_actor_update_opaque_region (self); + + if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11) + { + meta_window_actor_update_input_region (self); + meta_window_actor_update_opaque_region (self); + } priv->needs_reshape = FALSE; } @@ -2095,16 +1802,13 @@ meta_window_actor_update_shape (MetaWindowActor *self) if (is_frozen (self)) return; - clutter_actor_queue_redraw (priv->actor); + clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface)); } static void meta_window_actor_handle_updates (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); if (is_frozen (self)) { @@ -2113,42 +1817,14 @@ meta_window_actor_handle_updates (MetaWindowActor *self) return; } - if (priv->unredirected) - { - /* Nothing to do here until/if the window gets redirected again */ - return; - } + if (meta_surface_actor_is_unredirected (priv->surface)) + return; - if (priv->received_damage) - { - meta_error_trap_push (display); - XDamageSubtract (xdisplay, priv->damage, None, None); - meta_error_trap_pop (display); - - /* We need to make sure that any X drawing that happens before the - * XDamageSubtract() above is visible to subsequent GL rendering; - * the only standardized way to do this is EXT_x11_sync_object, - * which isn't yet widely available. For now, we count on details - * of Xorg and the open source drivers, and hope for the best - * otherwise. - * - * Xorg and open source driver specifics: - * - * The X server makes sure to flush drawing to the kernel before - * sending out damage events, but since we use DamageReportBoundingBox - * there may be drawing between the last damage event and the - * XDamageSubtract() that needs to be flushed as well. - * - * Xorg always makes sure that drawing is flushed to the kernel - * before writing events or responses to the client, so any round trip - * request at this point is sufficient to flush the GLX buffers. - */ - XSync (xdisplay, False); + meta_surface_actor_pre_paint (priv->surface); - priv->received_damage = FALSE; - } + if (!meta_surface_actor_is_visible (priv->surface)) + return; - check_needs_pixmap (self); check_needs_reshape (self); check_needs_shadow (self); } @@ -2177,8 +1853,7 @@ static void do_send_frame_drawn (MetaWindowActor *self, FrameData *frame) { MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); + MetaDisplay *display = meta_window_get_display (priv->window); Display *xdisplay = meta_display_get_xdisplay (display); XClientMessageEvent ev = { 0, }; @@ -2230,7 +1905,7 @@ do_send_frame_timings (MetaWindowActor *self, gint64 presentation_time) { MetaWindowActorPrivate *priv = self->priv; - MetaDisplay *display = meta_screen_get_display (priv->screen); + MetaDisplay *display = meta_window_get_display (priv->window); Display *xdisplay = meta_display_get_xdisplay (display); XClientMessageEvent ev = { 0, }; @@ -2329,7 +2004,8 @@ meta_window_actor_update_opacity (MetaWindowActor *self) MetaWindowActorPrivate *priv = self->priv; MetaWindow *window = priv->window; - clutter_actor_set_opacity (self->priv->actor, window->opacity); + if (priv->surface) + clutter_actor_set_opacity (CLUTTER_ACTOR (priv->surface), window->opacity); } void diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c index 49a58b7..4096e48 100644 --- a/src/compositor/meta-window-group.c +++ b/src/compositor/meta-window-group.c @@ -122,7 +122,6 @@ meta_window_group_paint (ClutterActor *actor) MetaWindowGroup *window_group = META_WINDOW_GROUP (actor); ClutterActor *stage = clutter_actor_get_stage (actor); - MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen); /* Normally we expect an actor to be drawn at it's position on the screen. * However, if we're inside the paint of a ClutterClone, that won't be the @@ -165,15 +164,6 @@ meta_window_group_paint (ClutterActor *actor) paint_y_offset = paint_y_origin - actor_y_origin; cairo_region_translate (clip_region, -paint_x_offset, -paint_y_offset); - if (info->unredirected_window != NULL) - { - cairo_rectangle_int_t unredirected_rect; - - meta_window_get_frame_rect (info->unredirected_window, (MetaRectangle *)&unredirected_rect); - cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect); - cairo_region_subtract_rectangle (clip_region, &unredirected_rect); - } - meta_cullable_cull_out (META_CULLABLE (window_group), unobscured_region, clip_region); cairo_region_destroy (unobscured_region); diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c index 0568953..1c1820f 100644 --- a/src/compositor/plugins/default.c +++ b/src/compositor/plugins/default.c @@ -32,7 +32,7 @@ #include <gmodule.h> #include <string.h> -#define DESTROY_TIMEOUT 250 +#define DESTROY_TIMEOUT 100 #define MINIMIZE_TIMEOUT 250 #define MAXIMIZE_TIMEOUT 250 #define MAP_TIMEOUT 250 @@ -488,8 +488,6 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data /* FIXME - we shouldn't assume the original scale, it should be saved * at the start of the effect */ clutter_actor_set_scale (data->actor, 1.0, 1.0); - clutter_actor_move_anchor_point_from_gravity (data->actor, - CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ meta_plugin_minimize_completed (plugin, window_actor); @@ -526,9 +524,6 @@ minimize (MetaPlugin *plugin, MetaWindowActor *window_actor) apriv->is_minimized = TRUE; - clutter_actor_move_anchor_point_from_gravity (actor, - CLUTTER_GRAVITY_CENTER); - animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MINIMIZE_TIMEOUT, @@ -567,8 +562,6 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data /* FIXME - don't assume the original scale was 1.0 */ clutter_actor_set_scale (data->actor, 1.0, 1.0); - clutter_actor_move_anchor_point_from_gravity (data->actor, - CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ meta_plugin_maximize_completed (plugin, window_actor); @@ -593,10 +586,8 @@ maximize (MetaPlugin *plugin, ClutterActor *actor = CLUTTER_ACTOR (window_actor); MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); - gdouble scale_x = 1.0; - gdouble scale_y = 1.0; - gfloat anchor_x = 0; - gfloat anchor_y = 0; + gdouble scale_x = 1.0; + gdouble scale_y = 1.0; type = meta_window_get_window_type (meta_window); @@ -620,13 +611,6 @@ maximize (MetaPlugin *plugin, scale_x = (gdouble)end_width / (gdouble) width; scale_y = (gdouble)end_height / (gdouble) height; - anchor_x = (gdouble)(x - end_x)*(gdouble)width / - ((gdouble)(end_width - width)); - anchor_y = (gdouble)(y - end_y)*(gdouble)height / - ((gdouble)(end_height - height)); - - clutter_actor_move_anchor_point (actor, anchor_x, anchor_y); - animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MAXIMIZE_TIMEOUT, @@ -681,9 +665,6 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data) apriv->tml_map = NULL; - clutter_actor_move_anchor_point_from_gravity (data->actor, - CLUTTER_GRAVITY_NORTH_WEST); - /* Now notify the manager that we are done with this effect */ meta_plugin_map_completed (plugin, window_actor); @@ -769,14 +750,12 @@ destroy (MetaPlugin *plugin, MetaWindowActor *window_actor) EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); - clutter_actor_move_anchor_point_from_gravity (actor, - CLUTTER_GRAVITY_CENTER); - animation = clutter_actor_animate (actor, - CLUTTER_EASE_IN_SINE, + CLUTTER_EASE_OUT_QUAD, DESTROY_TIMEOUT, - "scale-x", 0.0, - "scale-y", 1.0, + "opacity", 0, + "scale-x", 0.8, + "scale-y", 0.8, NULL); apriv->tml_destroy = clutter_animation_get_timeline (animation); data->plugin = plugin; diff --git a/src/core/above-tab-keycode.c b/src/core/above-tab-keycode.c deleted file mode 100644 index e980f52..0000000 --- a/src/core/above-tab-keycode.c +++ /dev/null @@ -1,241 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Find the keycode for the key above the tab key */ -/* - * Copyright 2010 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/* The standard cycle-windows keybinding should be the key above the - * tab key. This will have a different keysym on different keyboards - - * it's the ` (grave) key on US keyboards but something else on many - * other national layouts. So we need to figure out the keycode for - * this key without reference to key symbol. - * - * The "correct" way to do this is to get the XKB geometry from the - * X server, find the Tab key, find the key above the Tab key in the - * same section and use the keycode for that key. This is what I - * implemented here, but unfortunately, fetching the geometry is rather - * slow (It could take 20ms or more.) - * - * If you looking for a way to optimize Mutter startup performance: - * On all Linux systems using evdev the key above TAB will have - * keycode 49. (KEY_GRAVE=41 + the 8 code point offset between - * evdev keysyms and X keysyms.) So a configure option - * --with-above-tab-keycode=49 could be added that bypassed this - * code. It wouldn't work right for displaying Mutter remotely - * to a non-Linux X server, but that is pretty rare. - */ - -#include <config.h> - -#include <string.h> - -#include "display-private.h" - -#include <X11/keysym.h> - -#ifdef HAVE_XKB -#include <X11/XKBlib.h> -#include <X11/extensions/XKBgeom.h> - -static guint -compute_above_tab_keycode (Display *xdisplay) -{ - XkbDescPtr keyboard; - XkbGeometryPtr geometry; - int i, j, k; - int tab_keycode; - char *tab_name; - XkbSectionPtr tab_section; - XkbBoundsRec tab_bounds; - XkbKeyPtr best_key = NULL; - guint best_keycode = (guint)-1; - int best_x_dist = G_MAXINT; - int best_y_dist = G_MAXINT; - - /* We need only the Names and the Geometry, but asking for these results - * in the Keyboard information retrieval failing for unknown reasons. - * (Testing with xorg-1.9.1.) So we ask for a part that we don't need - * as well. - */ - keyboard = XkbGetKeyboard (xdisplay, - XkbGBN_ClientSymbolsMask | XkbGBN_KeyNamesMask | XkbGBN_GeometryMask, - XkbUseCoreKbd); - if (!keyboard) - return best_keycode; - - geometry = keyboard->geom; - - /* There could potentially be multiple keys with the Tab keysym on the keyboard; - * but XKeysymToKeycode() returns us the one that the alt-Tab binding will - * use which is good enough - */ - tab_keycode = XKeysymToKeycode (xdisplay, XK_Tab); - if (tab_keycode == 0 || tab_keycode < keyboard->min_key_code || tab_keycode > keyboard->max_key_code) - goto out; - - /* The keyboard geometry is stored by key "name" rather than keycode. - * (Key names are 4-character strings like like TAB or AE01.) We use the - * 'names' part of the keyboard description to map keycode to key name. - * - * XKB has a "key aliases" feature where a single keyboard key can have - * multiple names (with separate sets of aliases in the 'names' part and - * in the 'geometry' part), but I don't really understand it or how it is used, - * so I'm ignoring it here. - */ - - tab_name = keyboard->names->keys[tab_keycode].name; /* Not NULL terminated! */ - - /* First, iterate through the keyboard geometry to find the tab key; the keyboard - * geometry has a three-level heirarchy of section > row > key - */ - for (i = 0; i < geometry->num_sections; i++) - { - XkbSectionPtr section = &geometry->sections[i]; - for (j = 0; j < section->num_rows; j++) - { - int x = 0; - int y = 0; - - XkbRowPtr row = §ion->rows[j]; - for (k = 0; k < row->num_keys; k++) - { - XkbKeyPtr key = &row->keys[k]; - XkbShapePtr shape = XkbKeyShape (geometry, key); - - if (row->vertical) - y += key->gap; - else - x += key->gap; - - if (strncmp (key->name.name, tab_name, XkbKeyNameLength) == 0) - { - tab_section = section; - tab_bounds = shape->bounds; - tab_bounds.x1 += row->left + x; - tab_bounds.x2 += row->left + x; - tab_bounds.y1 += row->top + y; - tab_bounds.y2 += row->top + y; - - goto found_tab; - } - - if (row->vertical) - y += (shape->bounds.y2 - shape->bounds.y1); - else - x += (shape->bounds.x2 - shape->bounds.x1); - } - } - } - - /* No tab key found */ - goto out; - - found_tab: - - /* Now find the key that: - * - Is in the same section as the Tab key - * - Has a horizontal center in the Tab key's horizonal bounds - * - Is above the Tab key at a distance closer than any other key - * - In case of ties, has its horizontal center as close as possible - * to the Tab key's horizontal center - */ - for (j = 0; j < tab_section->num_rows; j++) - { - int x = 0; - int y = 0; - - XkbRowPtr row = &tab_section->rows[j]; - for (k = 0; k < row->num_keys; k++) - { - XkbKeyPtr key = &row->keys[k]; - XkbShapePtr shape = XkbKeyShape(geometry, key); - XkbBoundsRec bounds = shape->bounds; - int x_center; - int x_dist, y_dist; - - if (row->vertical) - y += key->gap; - else - x += key->gap; - - bounds.x1 += row->left + x; - bounds.x2 += row->left + x; - bounds.y1 += row->top + y; - bounds.y2 += row->top + y; - - y_dist = tab_bounds.y1 - bounds.y2; - if (y_dist < 0) - continue; - - x_center = (bounds.x1 + bounds.x2) / 2; - if (x_center < tab_bounds.x1 || x_center > tab_bounds.x2) - continue; - - x_dist = ABS (x_center - (tab_bounds.x1 + tab_bounds.x2) / 2); - - if (y_dist < best_y_dist || - (y_dist == best_y_dist && x_dist < best_x_dist)) - { - best_key = key; - best_x_dist = x_dist; - best_y_dist = y_dist; - } - - if (row->vertical) - y += (shape->bounds.y2 - shape->bounds.y1); - else - x += (shape->bounds.x2 - shape->bounds.x1); - } - } - - if (best_key == NULL) - goto out; - - /* Now we need to resolve the name of the best key back to a keycode */ - for (i = keyboard->min_key_code; i < keyboard->max_key_code; i++) - { - if (strncmp (best_key->name.name, keyboard->names->keys[i].name, XkbKeyNameLength) == 0) - { - best_keycode = i; - break; - } - } - - out: - XkbFreeKeyboard (keyboard, 0, True); - - return best_keycode; -} -#else /* !HAVE_XKB */ -static guint -compute_above_tab_keycode (Display *xdisplay) -{ - return XKeysymToKeycode (xdisplay, XK_grave); -} -#endif /* HAVE_XKB */ - -guint -meta_display_get_above_tab_keycode (MetaDisplay *display) -{ - if (display->above_tab_keycode == 0) /* not yet computed */ - display->above_tab_keycode = compute_above_tab_keycode (display->xdisplay); - - if (display->above_tab_keycode == (guint)-1) /* failed to compute */ - return 0; - else - return display->above_tab_keycode; -} diff --git a/src/core/barrier.c b/src/core/barrier.c index 643b26e..b869d2e 100644 --- a/src/core/barrier.c +++ b/src/core/barrier.c @@ -366,11 +366,25 @@ meta_barrier_fire_event (MetaBarrier *barrier, } gboolean -meta_display_process_barrier_event (MetaDisplay *display, - XIBarrierEvent *xev) +meta_display_process_barrier_event (MetaDisplay *display, + XIEvent *event) { MetaBarrier *barrier; + XIBarrierEvent *xev; + if (event == NULL) + return FALSE; + + switch (event->evtype) + { + case XI_BarrierHit: + case XI_BarrierLeave: + break; + default: + return FALSE; + } + + xev = (XIBarrierEvent *) event; barrier = g_hash_table_lookup (display->xids, &xev->barrier); if (barrier != NULL) { diff --git a/src/core/bell.c b/src/core/bell.c index cc25a27..0b1457b 100644 --- a/src/core/bell.c +++ b/src/core/bell.c @@ -59,88 +59,6 @@ #endif /** - * bell_flash_screen: - * @display: The display which owns the screen (rather redundant) - * @screen: The screen to flash - * - * Flashes one entire screen. This is done by making a window the size of the - * whole screen (or reusing the old one, if it's still around), mapping it, - * painting it white and then black, and then unmapping it. We set saveunder so - * that all the windows behind it come back immediately. - * - * Unlike frame flashes, we don't do fullscreen flashes with a timeout; rather, - * we do them in one go, because we don't have to rely on the theme code - * redrawing the frame for us in order to do the flash. - */ -/* - * Bug: The way I read it, this appears not to do the flash - * the first time we flash a particular display. Am I wrong? - * - * Bug: This appears to destroy our current XSync status. - */ -static void -bell_flash_screen (MetaDisplay *display, - MetaScreen *screen) -{ - Window root = screen->xroot; - int width = screen->rect.width; - int height = screen->rect.height; - - if (screen->flash_window == None) - { - Visual *visual = (Visual *)CopyFromParent; - XSetWindowAttributes xswa; - int depth = CopyFromParent; - xswa.save_under = True; - xswa.override_redirect = True; - /* - * TODO: use XGetVisualInfo and determine which is an - * overlay, if one is present, and use the Overlay visual - * for this window (for performance reasons). - * Not sure how to tell this yet... - */ - screen->flash_window = XCreateWindow (display->xdisplay, root, - 0, 0, width, height, - 0, depth, - InputOutput, - visual, - /* note: XSun doesn't like SaveUnder here */ - CWSaveUnder | CWOverrideRedirect, - &xswa); - XSelectInput (display->xdisplay, screen->flash_window, ExposureMask); - XMapWindow (display->xdisplay, screen->flash_window); - XSync (display->xdisplay, False); - XFlush (display->xdisplay); - XUnmapWindow (display->xdisplay, screen->flash_window); - } - else - { - /* just draw something in the window */ - GC gc = XCreateGC (display->xdisplay, screen->flash_window, 0, NULL); - XMapWindow (display->xdisplay, screen->flash_window); - XSetForeground (display->xdisplay, gc, - WhitePixel (display->xdisplay, - XScreenNumberOfScreen (screen->xscreen))); - XFillRectangle (display->xdisplay, screen->flash_window, gc, - 0, 0, width, height); - XSetForeground (display->xdisplay, gc, - BlackPixel (display->xdisplay, - XScreenNumberOfScreen (screen->xscreen))); - XFillRectangle (display->xdisplay, screen->flash_window, gc, - 0, 0, width, height); - XFlush (display->xdisplay); - XSync (display->xdisplay, False); - XUnmapWindow (display->xdisplay, screen->flash_window); - XFreeGC (display->xdisplay, gc); - } - - if (meta_prefs_get_focus_mode () != G_DESKTOP_FOCUS_MODE_CLICK && - !display->mouse_mode) - meta_display_increment_focus_sentinel (display); - XFlush (display->xdisplay); -} - -/** * bell_flash_fullscreen: * @display: The display the event came in on * @xkb_ev: The bell event @@ -156,34 +74,8 @@ static void bell_flash_fullscreen (MetaDisplay *display, XkbAnyEvent *xkb_ev) { - XkbBellNotifyEvent *xkb_bell_ev = (XkbBellNotifyEvent *) xkb_ev; - MetaScreen *screen; - g_assert (xkb_ev->xkb_type == XkbBellNotify); - if (xkb_bell_ev->window != None) - { - screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window); - if (screen) - { - if (display->compositor) - meta_compositor_flash_screen (display->compositor, screen); - else - bell_flash_screen (display, screen); - } - } - else - { - GSList *screen_list = display->screens; - while (screen_list) - { - screen = (MetaScreen *) screen_list->data; - if (display->compositor) - meta_compositor_flash_screen (display->compositor, screen); - else - bell_flash_screen (display, screen); - screen_list = screen_list->next; - } - } + meta_compositor_flash_screen (display->compositor, display->screen); } /** diff --git a/src/core/constraints.c b/src/core/constraints.c index c6950ce..8bb9b25 100644 --- a/src/core/constraints.c +++ b/src/core/constraints.c @@ -425,6 +425,7 @@ setup_constraint_info (ConstraintInfo *info, * the monitor. */ if (meta_prefs_get_force_fullscreen() && + window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND && !window->hide_titlebar_when_maximized && (window->decorated || !meta_window_is_client_decorated (window)) && meta_rectangle_equal (new, &monitor_info->rect) && diff --git a/src/core/constraints.h b/src/core/constraints.h index e5d29ca..9c3c41e 100644 --- a/src/core/constraints.h +++ b/src/core/constraints.h @@ -27,15 +27,6 @@ #include "window-private.h" #include "frame.h" -typedef enum -{ - META_IS_CONFIGURE_REQUEST = 1 << 0, - META_DO_GRAVITY_ADJUST = 1 << 1, - META_IS_USER_ACTION = 1 << 2, - META_IS_MOVE_ACTION = 1 << 3, - META_IS_RESIZE_ACTION = 1 << 4 -} MetaMoveResizeFlags; - void meta_window_constrain (MetaWindow *window, MetaMoveResizeFlags flags, int resize_gravity, diff --git a/src/core/core.c b/src/core/core.c index 319020d..a091bb8 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -153,7 +153,7 @@ meta_core_get (Display *xdisplay, break; default: - meta_warning(_("Unknown window information request: %d"), request); + meta_warning("Unknown window information request: %d\n", request); } request = va_arg (args, MetaCoreGetType); @@ -270,9 +270,11 @@ meta_core_lower_beneath_grab_window (Display *xdisplay, MetaDisplay *display; MetaScreen *screen; MetaWindow *grab_window; + MetaStackWindow stack_window; + MetaStackWindow stack_sibling; display = meta_display_for_x_display (xdisplay); - screen = meta_display_screen_for_xwindow (display, xwindow); + screen = display->screen; grab_window = display->grab_window; if (grab_window == NULL) @@ -281,9 +283,13 @@ meta_core_lower_beneath_grab_window (Display *xdisplay, changes.stack_mode = Below; changes.sibling = meta_window_get_toplevel_xwindow (grab_window); + stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_window.x11.xwindow = xwindow; + stack_sibling.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_sibling.x11.xwindow = changes.sibling; meta_stack_tracker_record_lower_below (screen->stack_tracker, - xwindow, - changes.sibling, + &stack_window, + &stack_sibling, XNextRequest (screen->display->xdisplay)); meta_error_trap_push (display); @@ -597,13 +603,10 @@ meta_core_get_workspace_name_with_index (Display *xdisplay, int index) { MetaDisplay *display; - MetaScreen *screen; MetaWorkspace *workspace; display = meta_display_for_x_display (xdisplay); - screen = meta_display_screen_for_root (display, xroot); - g_assert (screen != NULL); - workspace = meta_screen_get_workspace_by_index (screen, index); + workspace = meta_screen_get_workspace_by_index (display->screen, index); return workspace ? meta_workspace_get_name (workspace) : NULL; } @@ -624,7 +627,7 @@ meta_core_begin_grab_op (Display *xdisplay, MetaScreen *screen; display = meta_display_for_x_display (xdisplay); - screen = meta_display_screen_for_xwindow (display, frame_xwindow); + screen = display->screen; g_assert (screen != NULL); @@ -664,10 +667,6 @@ meta_core_get_grab_frame (Display *xdisplay) display = meta_display_for_x_display (xdisplay); g_assert (display != NULL); - g_assert (display->grab_op == META_GRAB_OP_NONE || - display->grab_screen != NULL); - g_assert (display->grab_op == META_GRAB_OP_NONE || - display->grab_screen->display->xdisplay == xdisplay); if (display->grab_op != META_GRAB_OP_NONE && display->grab_window && @@ -713,16 +712,6 @@ meta_core_set_screen_cursor (Display *xdisplay, } void -meta_core_increment_event_serial (Display *xdisplay) -{ - MetaDisplay *display; - - display = meta_display_for_x_display (xdisplay); - - meta_display_increment_event_serial (display); -} - -void meta_invalidate_default_icons (void) { MetaDisplay *display = meta_get_display (); diff --git a/src/core/core.h b/src/core/core.h index a332153..4c9e587 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -193,12 +193,6 @@ void meta_core_set_screen_cursor (Display *xdisplay, Window frame_on_screen, MetaCursor cursor); -/* Used because we ignore EnterNotify when a window is unmapped that - * really shouldn't cause focus changes, by comparing the event serial - * of the EnterNotify and the UnmapNotify. - */ -void meta_core_increment_event_serial (Display *display); - void meta_invalidate_default_icons (void); void meta_core_add_old_event_mask (Display *xdisplay, diff --git a/src/core/delete.c b/src/core/delete.c index 96e2ec5..8b50707 100644 --- a/src/core/delete.c +++ b/src/core/delete.c @@ -37,18 +37,17 @@ #include <stdlib.h> #include <stdio.h> +#include "wayland/meta-wayland-surface.h" + static void meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp); static void -delete_ping_reply_func (MetaDisplay *display, - Window xwindow, +delete_ping_reply_func (MetaWindow *window, guint32 timestamp, void *user_data) { - meta_topic (META_DEBUG_PING, - "Got reply to delete ping for %s\n", - ((MetaWindow*)user_data)->desc); + meta_topic (META_DEBUG_PING, "Got reply to delete ping for %s\n", window->desc); /* we do nothing */ } @@ -66,12 +65,10 @@ dialog_exited (GPid pid, int status, gpointer user_data) } static void -delete_ping_timeout_func (MetaDisplay *display, - Window xwindow, +delete_ping_timeout_func (MetaWindow *window, guint32 timestamp, void *user_data) { - MetaWindow *window = user_data; char *window_title; gchar *window_content, *tmp; GPid dialog_pid; @@ -135,36 +132,18 @@ void meta_window_check_alive (MetaWindow *window, guint32 timestamp) { - meta_display_ping_window (window->display, - window, + meta_display_ping_window (window, timestamp, delete_ping_reply_func, delete_ping_timeout_func, - window); + NULL); } void meta_window_delete (MetaWindow *window, guint32 timestamp) { - meta_error_trap_push (window->display); - if (window->delete_window) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Deleting %s with delete_window request\n", - window->desc); - meta_window_send_icccm_message (window, - window->display->atom_WM_DELETE_WINDOW, - timestamp); - } - else - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Deleting %s with explicit kill\n", - window->desc); - XKillClient (window->display->xdisplay, window->xwindow); - } - meta_error_trap_pop (window->display); + META_WINDOW_GET_CLASS (window)->delete (window, timestamp); meta_window_check_alive (window, timestamp); @@ -197,33 +176,10 @@ meta_window_delete (MetaWindow *window, } } - void meta_window_kill (MetaWindow *window) { - meta_topic (META_DEBUG_WINDOW_OPS, - "Killing %s brutally\n", - window->desc); - - if (!meta_window_is_remote (window) && - window->net_wm_pid > 0) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Killing %s with kill()\n", - window->desc); - - if (kill (window->net_wm_pid, 9) < 0) - meta_topic (META_DEBUG_WINDOW_OPS, - "Failed to signal %s: %s\n", - window->desc, strerror (errno)); - } - - meta_topic (META_DEBUG_WINDOW_OPS, - "Disconnecting %s with XKillClient()\n", - window->desc); - meta_error_trap_push (window->display); - XKillClient (window->display->xdisplay, window->xwindow); - meta_error_trap_pop (window->display); + META_WINDOW_GET_CLASS (window)->kill (window); } void @@ -258,8 +214,7 @@ meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp) { MetaWindow *w = tmp->data; - if (w->xtransient_for == window->xwindow && - w->res_class && + if (w->transient_for == window && w->res_class && g_ascii_strcasecmp (w->res_class, "mutter-dialog") == 0) { meta_window_activate (w, timestamp); diff --git a/src/core/display-private.h b/src/core/display-private.h index 5c47d12..8209c8f 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -37,6 +37,7 @@ #include "keybindings-private.h" #include <meta/prefs.h> #include <meta/barrier.h> +#include <clutter/clutter.h> #ifdef HAVE_STARTUP_NOTIFICATION #include <libsn/sn.h> @@ -54,10 +55,9 @@ typedef struct _MetaWindowPropHooks MetaWindowPropHooks; typedef struct MetaEdgeResistanceData MetaEdgeResistanceData; -typedef void (* MetaWindowPingFunc) (MetaDisplay *display, - Window xwindow, - guint32 timestamp, - gpointer user_data); +typedef void (* MetaWindowPingFunc) (MetaWindow *window, + guint32 timestamp, + gpointer user_data); typedef enum { META_LIST_DEFAULT = 0, /* normal windows */ @@ -91,6 +91,8 @@ struct _MetaDisplay char *name; Display *xdisplay; + int clutter_event_filter; + Window leader_window; Window timestamp_pinging_window; @@ -143,17 +145,12 @@ struct _MetaDisplay * multiple events with the same serial. */ guint focused_by_us : 1; - - guint static_gravity_works : 1; /*< private-ish >*/ - guint error_trap_synced_at_last_pop : 1; - GSList *screens; - MetaScreen *active_screen; + MetaScreen *screen; GHashTable *xids; - int error_traps; - int (* error_trap_handler) (Display *display, - XErrorEvent *error); + GHashTable *wayland_windows; + int server_grab_count; /* serials of leave/unmap events that may @@ -185,11 +182,10 @@ struct _MetaDisplay MetaWindow* autoraise_window; /* Alt+click button grabs */ - unsigned int window_grab_modifiers; + ClutterModifierType window_grab_modifiers; /* current window operation */ MetaGrabOp grab_op; - MetaScreen *grab_screen; MetaWindow *grab_window; Window grab_xwindow; int grab_button; @@ -200,7 +196,6 @@ struct _MetaDisplay int grab_tile_monitor_number; int grab_latest_motion_x; int grab_latest_motion_y; - gulong grab_mask; guint grab_have_pointer : 1; guint grab_have_keyboard : 1; guint grab_frame_action : 1; @@ -212,7 +207,6 @@ struct _MetaDisplay gboolean grab_threshold_movement_reached; /* raise_on_click == FALSE. */ MetaResizePopup *grab_resize_popup; GTimeVal grab_last_moveresize_time; - guint32 grab_motion_notify_time; GList* grab_old_window_stacking; MetaEdgeResistanceData *grab_edge_resistance_data; unsigned int grab_last_user_action_was_snap; @@ -236,11 +230,7 @@ struct _MetaDisplay int max_keycode; KeySym *keymap; int keysyms_per_keycode; - XModifierKeymap *modmap; - unsigned int above_tab_keycode; unsigned int ignored_modifier_mask; - unsigned int num_lock_mask; - unsigned int scroll_lock_mask; unsigned int hyper_mask; unsigned int super_mask; unsigned int meta_mask; @@ -351,10 +341,6 @@ struct _MetaDisplayClass gboolean meta_display_open (void); void meta_display_close (MetaDisplay *display, guint32 timestamp); -MetaScreen* meta_display_screen_for_x_screen (MetaDisplay *display, - Screen *screen); -MetaScreen* meta_display_screen_for_xwindow (MetaDisplay *display, - Window xindow); void meta_display_grab (MetaDisplay *display); void meta_display_ungrab (MetaDisplay *display); @@ -377,6 +363,11 @@ void meta_display_register_x_window (MetaDisplay *display, void meta_display_unregister_x_window (MetaDisplay *display, Window xwindow); +void meta_display_register_wayland_window (MetaDisplay *display, + MetaWindow *window); +void meta_display_unregister_wayland_window (MetaDisplay *display, + MetaWindow *window); + #ifdef HAVE_XSYNC MetaWindow* meta_display_lookup_sync_alarm (MetaDisplay *display, XSyncAlarm alarm); @@ -436,20 +427,22 @@ void meta_display_retheme_all (void); void meta_display_set_cursor_theme (const char *theme, int size); -void meta_display_ping_window (MetaDisplay *display, - MetaWindow *window, +void meta_display_ping_window (MetaWindow *window, guint32 timestamp, MetaWindowPingFunc ping_reply_func, MetaWindowPingFunc ping_timeout_func, void *user_data); -gboolean meta_display_window_has_pending_pings (MetaDisplay *display, - MetaWindow *window); +void meta_display_pong_for_serial (MetaDisplay *display, + guint32 serial); int meta_resize_gravity_from_grab_op (MetaGrabOp op); gboolean meta_grab_op_is_moving (MetaGrabOp op); gboolean meta_grab_op_is_resizing (MetaGrabOp op); gboolean meta_grab_op_is_mouse (MetaGrabOp op); +gboolean meta_grab_op_is_clicking (MetaGrabOp op); +gboolean meta_grab_op_is_wayland (MetaGrabOp op); +gboolean meta_grab_op_is_keyboard (MetaGrabOp op); void meta_display_devirtualize_modifiers (MetaDisplay *display, MetaVirtualModifier modifiers, @@ -464,18 +457,14 @@ void meta_display_queue_autoraise_callback (MetaDisplay *display, void meta_display_remove_autoraise_callback (MetaDisplay *display); void meta_display_overlay_key_activate (MetaDisplay *display); -void meta_display_accelerator_activate (MetaDisplay *display, - guint action, - guint deviceid, - guint timestamp); +void meta_display_accelerator_activate (MetaDisplay *display, + guint action, + ClutterKeyEvent *event); gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display); -/* In above-tab-keycode.c */ -guint meta_display_get_above_tab_keycode (MetaDisplay *display); - #ifdef HAVE_XI23 -gboolean meta_display_process_barrier_event (MetaDisplay *display, - XIBarrierEvent *event); +gboolean meta_display_process_barrier_event (MetaDisplay *display, + XIEvent *event); #endif /* HAVE_XI23 */ void meta_display_set_input_focus_xwindow (MetaDisplay *display, @@ -483,4 +472,16 @@ void meta_display_set_input_focus_xwindow (MetaDisplay *display, Window window, guint32 timestamp); +void meta_display_sync_wayland_input_focus (MetaDisplay *display); +void meta_display_update_focus_window (MetaDisplay *display, + MetaWindow *window, + Window xwindow, + gulong serial, + gboolean focused_by_us); + +void meta_display_sanity_check_timestamps (MetaDisplay *display, + guint32 timestamp); +gboolean meta_display_timestamp_too_old (MetaDisplay *display, + guint32 *timestamp); + #endif diff --git a/src/core/display.c b/src/core/display.c index e8a284f..4556389 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -32,25 +32,24 @@ #include <config.h> #include "display-private.h" +#include "events.h" #include "util-private.h" #include <meta/main.h> #include "screen-private.h" #include "window-private.h" -#include "window-props.h" -#include "group-props.h" #include "frame.h" #include <meta/errors.h> #include "keybindings-private.h" #include <meta/prefs.h> #include "resizepopup.h" -#include "xprops.h" #include "workspace-private.h" #include "bell.h" #include <meta/compositor.h> #include <meta/compositor-mutter.h> #include <X11/Xatom.h> #include "mutter-enum-types.h" -#include "meta-idle-monitor-private.h" +#include "meta-idle-monitor-dbus.h" +#include "meta-cursor-tracker-private.h" #ifdef HAVE_RANDR #include <X11/extensions/Xrandr.h> @@ -58,12 +57,7 @@ #ifdef HAVE_SHAPE #include <X11/extensions/shape.h> #endif -#ifdef HAVE_XKB -#include <X11/XKBlib.h> -#endif -#ifdef HAVE_XCURSOR #include <X11/Xcursor/Xcursor.h> -#endif #include <X11/extensions/Xrender.h> #include <X11/extensions/Xcomposite.h> #include <X11/extensions/Xdamage.h> @@ -72,6 +66,14 @@ #include <string.h> #include <unistd.h> +#include "x11/window-x11.h" +#include "x11/window-props.h" +#include "x11/group-props.h" +#include "x11/xprops.h" + +#include "wayland/meta-xwayland-private.h" +#include "meta-surface-actor-wayland.h" + /* * SECTION:pings * @@ -96,10 +98,9 @@ * does or doesn't respond to the ping, we use this information to deal with * these facts; we have a handler function for each. */ -typedef struct +typedef struct { - MetaDisplay *display; - Window xwindow; + MetaWindow *window; guint32 timestamp; MetaWindowPingFunc ping_reply_func; MetaWindowPingFunc ping_timeout_func; @@ -107,15 +108,6 @@ typedef struct guint ping_timeout_id; } MetaPingData; -typedef struct -{ - MetaDisplay *display; - MetaWindow *window; - int pointer_x; - int pointer_y; -} MetaFocusData; - - G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT); /* Signals */ @@ -153,36 +145,10 @@ static MetaDisplay *the_display = NULL; static const char *gnome_wm_keybindings = "Mutter"; static const char *net_wm_name = "Mutter"; -#ifdef WITH_VERBOSE_MODE -static void meta_spew_event (MetaDisplay *display, - XEvent *event); -#endif - -static gboolean event_callback (XEvent *event, - gpointer data); -static Window event_get_modified_window (MetaDisplay *display, - XEvent *event); -static guint32 event_get_time (MetaDisplay *display, - XEvent *event); -static void process_request_frame_extents (MetaDisplay *display, - XEvent *event); -static void process_pong_message (MetaDisplay *display, - XEvent *event); -static void process_selection_request (MetaDisplay *display, - XEvent *event); -static void process_selection_clear (MetaDisplay *display, - XEvent *event); - static void update_window_grab_modifiers (MetaDisplay *display); static void prefs_changed_callback (MetaPreference pref, void *data); - -static void sanity_check_timestamps (MetaDisplay *display, - guint32 known_good_timestamp); - -MetaGroup* get_focussed_group (MetaDisplay *display); - static void meta_display_get_property(GObject *object, guint prop_id, @@ -347,14 +313,14 @@ remove_pending_pings_for_window (MetaDisplay *display, Window xwindow) GSList *dead; /* could obviously be more efficient, don't care */ - + /* build list to be removed */ dead = NULL; for (tmp = display->pending_pings; tmp; tmp = tmp->next) { MetaPingData *ping_data = tmp->data; - if (ping_data->xwindow == xwindow) + if (ping_data->window->xwindow == xwindow) dead = g_slist_prepend (dead, ping_data); } @@ -396,13 +362,11 @@ sn_error_trap_pop (SnDisplay *sn_display, static void enable_compositor (MetaDisplay *display) { - GSList *list; - if (!META_DISPLAY_HAS_COMPOSITE (display) || !META_DISPLAY_HAS_DAMAGE (display) || !META_DISPLAY_HAS_RENDER (display)) { - meta_warning (_("Missing %s extension required for compositing"), + meta_warning ("Missing %s extension required for compositing", !META_DISPLAY_HAS_COMPOSITE (display) ? "composite" : !META_DISPLAY_HAS_DAMAGE (display) ? "damage" : "render"); return; @@ -413,14 +377,8 @@ enable_compositor (MetaDisplay *display) if (!display->compositor) return; - - for (list = display->screens; list != NULL; list = list->next) - { - MetaScreen *screen = list->data; - - meta_compositor_manage_screen (screen->display->compositor, - screen); - } + + meta_compositor_manage (display->compositor); } static void @@ -474,9 +432,7 @@ gboolean meta_display_open (void) { Display *xdisplay; - GSList *screens; MetaScreen *screen; - GSList *tmp; int i; guint32 timestamp; @@ -499,6 +455,9 @@ meta_display_open (void) return FALSE; } + if (meta_is_wayland_compositor ()) + meta_xwayland_complete_init (); + if (meta_is_syncing ()) XSynchronize (xdisplay, True); @@ -513,9 +472,6 @@ meta_display_open (void) */ the_display->name = g_strdup (XDisplayName (NULL)); the_display->xdisplay = xdisplay; - the_display->error_trap_synced_at_last_pop = TRUE; - the_display->error_traps = 0; - the_display->error_trap_handler = NULL; the_display->server_grab_count = 0; the_display->display_opening = TRUE; @@ -531,9 +487,6 @@ meta_display_open (void) the_display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */ the_display->allow_terminal_deactivation = TRUE; /* Only relevant for when a terminal has the focus */ - - /* FIXME copy the checks from GDK probably */ - the_display->static_gravity_works = g_getenv ("MUTTER_USE_STATIC_GRAVITY") != NULL; meta_bell_init (the_display); @@ -571,8 +524,7 @@ meta_display_open (void) the_display->window_with_menu = NULL; the_display->window_menu = NULL; - the_display->screens = NULL; - the_display->active_screen = NULL; + the_display->screen = NULL; #ifdef HAVE_STARTUP_NOTIFICATION the_display->sn_display = sn_display_new (the_display->xdisplay, @@ -581,12 +533,11 @@ meta_display_open (void) #endif /* Get events */ - meta_ui_add_event_func (the_display->xdisplay, - event_callback, - the_display); - + meta_display_init_events (the_display); + the_display->xids = g_hash_table_new (meta_unsigned_long_hash, meta_unsigned_long_equal); + the_display->wayland_windows = g_hash_table_new (NULL, NULL); i = 0; while (i < N_IGNORED_CROSSING_SERIALS) @@ -608,7 +559,6 @@ meta_display_open (void) the_display->grab_op = META_GRAB_OP_NONE; the_display->grab_window = NULL; - the_display->grab_screen = NULL; the_display->grab_resize_popup = NULL; the_display->grab_tile_mode = META_TILE_NONE; the_display->grab_tile_monitor_number = -1; @@ -806,14 +756,10 @@ meta_display_open (void) meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n"); } -#ifdef HAVE_XCURSOR { XcursorSetTheme (the_display->xdisplay, meta_prefs_get_cursor_theme ()); XcursorSetDefaultSize (the_display->xdisplay, meta_prefs_get_cursor_size ()); } -#else /* HAVE_XCURSOR */ - meta_verbose ("Not compiled with Xcursor support\n"); -#endif /* !HAVE_XCURSOR */ /* Create the leader window here. Set its properties and * use the timestamp from one of the PropertyNotify events @@ -881,23 +827,15 @@ meta_display_open (void) the_display->last_focus_time = timestamp; the_display->last_user_time = timestamp; the_display->compositor = NULL; - + /* Mutter used to manage all X screens of the display in a single process, but * now it always manages exactly one screen as specified by the DISPLAY - * environment variable. The screens GSList is left for simplicity. + * environment variable. */ - screens = NULL; - i = meta_ui_get_screen_number (); - screen = meta_screen_new (the_display, i, timestamp); - if (screen) - screens = g_slist_prepend (screens, screen); - - the_display->screens = screens; - - if (screens == NULL) + if (!screen) { /* This would typically happen because all the screens already * have window managers. @@ -906,18 +844,17 @@ meta_display_open (void) return FALSE; } + the_display->screen = screen; + enable_compositor (the_display); - - /* Now manage all existing windows */ - tmp = the_display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_screen_manage_all_windows (screen); - tmp = tmp->next; - } + meta_screen_create_guard_window (screen); + + /* We know that if mutter is running as a Wayland compositor, + * we start out with no windows. + */ + if (!meta_is_wayland_compositor ()) + meta_screen_manage_all_windows (screen); { Window focus; @@ -939,7 +876,7 @@ meta_display_open (void) if (focus == None || focus == PointerRoot) /* Just focus the no_focus_window on the first screen */ meta_display_focus_the_no_focus_window (the_display, - the_display->screens->data, + the_display->screen, timestamp); else { @@ -950,7 +887,7 @@ meta_display_open (void) else /* Just focus the no_focus_window on the first screen */ meta_display_focus_the_no_focus_window (the_display, - the_display->screens->data, + the_display->screen, timestamp); } @@ -992,8 +929,8 @@ meta_display_list_windows (MetaDisplay *display, MetaListWindowsFlags flags) { GSList *winlist; - GSList *tmp; GSList *prev; + GSList *tmp; GHashTableIter iter; gpointer key, value; @@ -1012,6 +949,19 @@ meta_display_list_windows (MetaDisplay *display, winlist = g_slist_prepend (winlist, window); } + g_hash_table_iter_init (&iter, display->wayland_windows); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + MetaWindow *window = value; + + if (!META_IS_WINDOW (window)) + continue; + + if (!window->override_redirect || + (flags & META_LIST_INCLUDE_OVERRIDE_REDIRECT) != 0) + winlist = g_slist_prepend (winlist, window); + } + /* Uniquify the list, since both frame windows and plain * windows are in the hash */ @@ -1055,8 +1005,6 @@ void meta_display_close (MetaDisplay *display, guint32 timestamp) { - GSList *tmp; - g_assert (display != NULL); if (display->closing != 0) @@ -1065,9 +1013,6 @@ meta_display_close (MetaDisplay *display, return; } - if (display->error_traps > 0) - meta_bug ("Display closed with error traps pending\n"); - display->closing += 1; meta_prefs_remove_listener (prefs_changed_callback, display); @@ -1080,23 +1025,11 @@ meta_display_close (MetaDisplay *display, if (display->grab_old_window_stacking) g_list_free (display->grab_old_window_stacking); - + /* Stop caring about events */ - meta_ui_remove_event_func (display->xdisplay, - event_callback, - display); + meta_display_free_events (display); - /* Free all screens */ - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - meta_screen_free (screen, timestamp); - tmp = tmp->next; - } - - g_slist_free (display->screens); - display->screens = NULL; + meta_screen_free (display->screen, timestamp); #ifdef HAVE_STARTUP_NOTIFICATION if (display->sn_display) @@ -1132,77 +1065,6 @@ meta_display_close (MetaDisplay *display, meta_quit (META_EXIT_SUCCESS); } -/** - * meta_display_screen_for_root: - * @display: a #MetaDisplay - * @xroot: a X window - * - * Return the #MetaScreen corresponding to a specified X root window ID. - * - * Return Value: (transfer none): the screen for the specified root window ID, or %NULL - */ -MetaScreen* -meta_display_screen_for_root (MetaDisplay *display, - Window xroot) -{ - GSList *tmp; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - if (xroot == screen->xroot) - return screen; - - tmp = tmp->next; - } - - return NULL; -} - -MetaScreen* -meta_display_screen_for_xwindow (MetaDisplay *display, - Window xwindow) -{ - XWindowAttributes attr; - int result; - - meta_error_trap_push (display); - attr.screen = NULL; - result = XGetWindowAttributes (display->xdisplay, xwindow, &attr); - meta_error_trap_pop (display); - - /* Note, XGetWindowAttributes is on all kinds of crack - * and returns 1 on success 0 on failure, rather than Success - * on success. - */ - if (result == 0 || attr.screen == NULL) - return NULL; - - return meta_display_screen_for_x_screen (display, attr.screen); -} - -MetaScreen* -meta_display_screen_for_x_screen (MetaDisplay *display, - Screen *xscreen) -{ - GSList *tmp; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - if (xscreen == screen->xscreen) - return screen; - - tmp = tmp->next; - } - - return NULL; -} - /* Grab/ungrab routines taken from fvwm. * Calling this function will cause X to ignore all other clients until * you ungrab. This may not be quite as bad as it sounds, yet there is @@ -1286,10 +1148,6 @@ meta_get_display (void) return the_display; } -#ifdef WITH_VERBOSE_MODE -static gboolean dump_events = TRUE; -#endif - static gboolean grab_op_is_mouse_only (MetaGrabOp op) { @@ -1343,8 +1201,8 @@ meta_grab_op_is_mouse (MetaGrabOp op) } } -static gboolean -grab_op_is_keyboard (MetaGrabOp op) +gboolean +meta_grab_op_is_keyboard (MetaGrabOp op) { switch (op) { @@ -1409,6 +1267,35 @@ meta_grab_op_is_moving (MetaGrabOp op) } } +gboolean +meta_grab_op_is_clicking (MetaGrabOp grab_op) +{ + switch (grab_op) + { + case META_GRAB_OP_CLICKING_MINIMIZE: + case META_GRAB_OP_CLICKING_MAXIMIZE: + case META_GRAB_OP_CLICKING_UNMAXIMIZE: + case META_GRAB_OP_CLICKING_DELETE: + case META_GRAB_OP_CLICKING_MENU: + case META_GRAB_OP_CLICKING_SHADE: + case META_GRAB_OP_CLICKING_UNSHADE: + case META_GRAB_OP_CLICKING_ABOVE: + case META_GRAB_OP_CLICKING_UNABOVE: + case META_GRAB_OP_CLICKING_STICK: + case META_GRAB_OP_CLICKING_UNSTICK: + return TRUE; + + default: + return FALSE; + } +} + +gboolean +meta_grab_op_is_wayland (MetaGrabOp op) +{ + return (op != META_GRAB_OP_NONE && !meta_grab_op_is_clicking (op)); +} + /** * meta_display_xserver_time_is_before: * @display: a #MetaDisplay @@ -1485,25 +1372,12 @@ meta_display_get_current_time_roundtrip (MetaDisplay *display) timestamp = property_event.xproperty.time; } - sanity_check_timestamps (display, timestamp); + meta_display_sanity_check_timestamps (display, timestamp); return timestamp; } /** - * meta_display_get_ignored_modifier_mask: - * @display: a #MetaDisplay - * - * Returns: a mask of modifiers that should be ignored - * when matching keybindings to events - */ -unsigned int -meta_display_get_ignored_modifier_mask (MetaDisplay *display) -{ - return display->ignored_modifier_mask; -} - -/** * meta_display_add_ignored_crossing_serial: * @display: a #MetaDisplay * @serial: the serial to ignore @@ -1535,37 +1409,6 @@ meta_display_add_ignored_crossing_serial (MetaDisplay *display, display->ignored_crossing_serials[i] = serial; } -static gboolean -crossing_serial_is_ignored (MetaDisplay *display, - unsigned long serial) -{ - int i; - - i = 0; - while (i < N_IGNORED_CROSSING_SERIALS) - { - if (display->ignored_crossing_serials[i] == serial) - return TRUE; - ++i; - } - return FALSE; -} - -static void -reset_ignored_crossing_serials (MetaDisplay *display) -{ - int i; - - i = 0; - while (i < N_IGNORED_CROSSING_SERIALS) - { - display->ignored_crossing_serials[i] = 0; - ++i; - } - - display->ungrab_should_not_cause_focus_window = None; -} - static gboolean window_raise_with_delay_callback (void *data) { @@ -1606,110 +1449,6 @@ window_raise_with_delay_callback (void *data) return FALSE; } -static void -meta_display_mouse_mode_focus (MetaDisplay *display, - MetaWindow *window, - guint32 timestamp) -{ - if (window->type != META_WINDOW_DESKTOP) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing %s at time %u.\n", window->desc, timestamp); - - meta_window_focus (window, timestamp); - - if (meta_prefs_get_auto_raise ()) - meta_display_queue_autoraise_callback (display, window); - else - meta_topic (META_DEBUG_FOCUS, "Auto raise is disabled\n"); - } - else - { - /* In mouse focus mode, we defocus when the mouse *enters* - * the DESKTOP window, instead of defocusing on LeaveNotify. - * This is because having the mouse enter override-redirect - * child windows unfortunately causes LeaveNotify events that - * we can't distinguish from the mouse actually leaving the - * toplevel window as we expect. But, since we filter out - * EnterNotify events on override-redirect windows, this - * alternative mechanism works great. - */ - if (meta_prefs_get_focus_mode() == G_DESKTOP_FOCUS_MODE_MOUSE && - display->focus_window != NULL) - { - meta_topic (META_DEBUG_FOCUS, - "Unsetting focus from %s due to mouse entering " - "the DESKTOP window\n", - display->focus_window->desc); - meta_display_focus_the_no_focus_window (display, - window->screen, - timestamp); - } - } -} - -static gboolean -window_focus_on_pointer_rest_callback (gpointer data) -{ - MetaFocusData *focus_data; - MetaDisplay *display; - MetaScreen *screen; - MetaWindow *window; - Window root, child; - double root_x, root_y, x, y; - guint32 timestamp; - XIButtonState buttons; - XIModifierState mods; - XIGroupState group; - - focus_data = data; - display = focus_data->display; - screen = focus_data->window->screen; - - if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) - goto out; - - meta_error_trap_push (display); - XIQueryPointer (display->xdisplay, - META_VIRTUAL_CORE_POINTER_ID, - screen->xroot, - &root, &child, - &root_x, &root_y, &x, &y, - &buttons, &mods, &group); - meta_error_trap_pop (display); - free (buttons.mask); - - if (root_x != focus_data->pointer_x || - root_y != focus_data->pointer_y) - { - focus_data->pointer_x = root_x; - focus_data->pointer_y = root_y; - return TRUE; - } - - /* Explicitly check for the overlay window, as get_focus_window_at_point() - * may return windows that extend underneath the chrome (like - * override-redirect or DESKTOP windows) - */ - if (child == meta_get_overlay_window (screen)) - goto out; - - window = - meta_stack_get_default_focus_window_at_point (screen->stack, - screen->active_workspace, - None, root_x, root_y); - - if (window == NULL) - goto out; - - timestamp = meta_display_get_current_time_roundtrip (display); - meta_display_mouse_mode_focus (display, window, timestamp); - - out: - display->focus_timeout_id = 0; - return FALSE; -} - void meta_display_queue_autoraise_callback (MetaDisplay *display, MetaWindow *window) @@ -1730,37 +1469,6 @@ meta_display_queue_autoraise_callback (MetaDisplay *display, display->autoraise_window = window; } -/* The interval, in milliseconds, we use in focus-follows-mouse - * mode to check whether the pointer has stopped moving after a - * crossing event. - */ -#define FOCUS_TIMEOUT_DELAY 25 - -static void -meta_display_queue_focus_callback (MetaDisplay *display, - MetaWindow *window, - int pointer_x, - int pointer_y) -{ - MetaFocusData *focus_data; - - focus_data = g_new (MetaFocusData, 1); - focus_data->display = display; - focus_data->window = window; - focus_data->pointer_x = pointer_x; - focus_data->pointer_y = pointer_y; - - if (display->focus_timeout_id != 0) - g_source_remove (display->focus_timeout_id); - - display->focus_timeout_id = - g_timeout_add_full (G_PRIORITY_DEFAULT, - FOCUS_TIMEOUT_DELAY, - window_focus_on_pointer_rest_callback, - focus_data, - g_free); -} - #if 0 static void handle_net_restack_window (MetaDisplay* display, @@ -1778,7 +1486,7 @@ handle_net_restack_window (MetaDisplay* display, * * Also, unconditionally following these is REALLY stupid--we should * combine this code with the stuff in - * meta_window_configure_request() which is smart about whether to + * meta_window_x11_configure_request() which is smart about whether to * follow the request or do something else (though not smart enough * and is also too stupid to handle the sibling stuff). */ @@ -1799,72 +1507,41 @@ handle_net_restack_window (MetaDisplay* display, } #endif -static XIEvent * -get_input_event (MetaDisplay *display, - XEvent *event) +void +meta_display_sync_wayland_input_focus (MetaDisplay *display) { - if (event->type == GenericEvent && - event->xcookie.extension == display->xinput_opcode) - { - XIEvent *input_event; + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + MetaWindow *focus_window = NULL; - /* NB: GDK event filters already have generic events - * allocated, so no need to do XGetEventData() on our own - */ - input_event = (XIEvent *) event->xcookie.data; + if (meta_grab_op_is_wayland (display->grab_op)) + focus_window = NULL; + else if (meta_display_xwindow_is_a_no_focus_window (display, display->focus_xwindow)) + focus_window = NULL; + else if (display->focus_window && display->focus_window->surface) + focus_window = display->focus_window; + else + meta_topic (META_DEBUG_FOCUS, "Focus change has no effect, because there is no matching wayland surface"); - switch (input_event->evtype) - { - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: - case XI_Motion: - case XI_ButtonPress: - case XI_ButtonRelease: - if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) - return input_event; - break; - case XI_KeyPress: - case XI_KeyRelease: - if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID) - return input_event; - break; - case XI_FocusIn: - case XI_FocusOut: - if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID) - return input_event; - break; - case XI_Enter: - case XI_Leave: - if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) - return input_event; - break; -#ifdef HAVE_XI23 - case XI_BarrierHit: - case XI_BarrierLeave: - if (((XIBarrierEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) - return input_event; - break; -#endif /* HAVE_XI23 */ - default: - break; - } - } + meta_wayland_compositor_set_input_focus (compositor, focus_window); - return NULL; + if (meta_grab_op_is_wayland (display->grab_op)) + meta_wayland_pointer_set_focus (&compositor->seat->pointer, NULL); + else + meta_wayland_seat_repick (compositor->seat, NULL); } -static void -update_focus_window (MetaDisplay *display, - MetaWindow *window, - Window xwindow, - gulong serial, - gboolean focused_by_us) +void +meta_display_update_focus_window (MetaDisplay *display, + MetaWindow *window, + Window xwindow, + gulong serial, + gboolean focused_by_us) { display->focus_serial = serial; display->focused_by_us = focused_by_us; - if (display->focus_xwindow == xwindow) + if (display->focus_xwindow == xwindow && + display->focus_window == window) return; if (display->focus_window) @@ -1898,13 +1575,16 @@ update_focus_window (MetaDisplay *display, else meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL with serial %lu\n", serial); + if (meta_is_wayland_compositor ()) + meta_display_sync_wayland_input_focus (display); + g_object_notify (G_OBJECT (display), "focus-window"); meta_display_update_active_window_hint (display); } -static gboolean -timestamp_too_old (MetaDisplay *display, - guint32 *timestamp) +gboolean +meta_display_timestamp_too_old (MetaDisplay *display, + guint32 *timestamp) { /* FIXME: If Soeren's suggestion in bug 151984 is implemented, it will allow * us to sanity check the timestamp here and ensure it doesn't correspond to @@ -1934,17 +1614,15 @@ timestamp_too_old (MetaDisplay *display, static void request_xserver_input_focus_change (MetaDisplay *display, MetaScreen *screen, + MetaWindow *meta_window, Window xwindow, guint32 timestamp) { - MetaWindow *meta_window; gulong serial; - if (timestamp_too_old (display, ×tamp)) + if (meta_display_timestamp_too_old (display, ×tamp)) return; - meta_window = meta_display_lookup_x_window (display, xwindow); - meta_error_trap_push (display); /* In order for mutter to know that the focus request succeeded, we track @@ -1970,1830 +1648,20 @@ request_xserver_input_focus_change (MetaDisplay *display, meta_display_ungrab (display); - update_focus_window (display, - meta_window, - xwindow, - serial, - TRUE); + meta_display_update_focus_window (display, + meta_window, + xwindow, + serial, + TRUE); meta_error_trap_pop (display); display->last_focus_time = timestamp; - display->active_screen = screen; if (meta_window == NULL || meta_window != display->autoraise_window) meta_display_remove_autoraise_callback (display); } -static void -handle_window_focus_event (MetaDisplay *display, - MetaWindow *window, - XIEnterEvent *event, - unsigned long serial) -{ - MetaWindow *focus_window; -#ifdef WITH_VERBOSE_MODE - const char *window_type; - - /* Note the event can be on either the window or the frame, - * we focus the frame for shaded windows - */ - if (window) - { - if (event->event == window->xwindow) - window_type = "client window"; - else if (window->frame && event->event == window->frame->xwindow) - window_type = "frame window"; - else - window_type = "unknown client window"; - } - else if (meta_display_xwindow_is_a_no_focus_window (display, event->event)) - window_type = "no_focus_window"; - else if (meta_display_screen_for_root (display, event->event)) - window_type = "root window"; - else - window_type = "unknown window"; - - meta_topic (META_DEBUG_FOCUS, - "Focus %s event received on %s 0x%lx (%s) " - "mode %s detail %s serial %lu\n", - event->evtype == XI_FocusIn ? "in" : - event->evtype == XI_FocusOut ? "out" : - "???", - window ? window->desc : "", - event->event, window_type, - meta_event_mode_to_string (event->mode), - meta_event_detail_to_string (event->mode), - event->serial); -#endif - - /* FIXME our pointer tracking is broken; see how - * gtk+/gdk/x11/gdkevents-x11.c or XFree86/xc/programs/xterm/misc.c - * for how to handle it the correct way. In brief you need to track - * pointer focus and regular focus, and handle EnterNotify in - * PointerRoot mode with no window manager. However as noted above, - * accurate focus tracking will break things because we want to keep - * windows "focused" when using keybindings on them, and also we - * sometimes "focus" a window by focusing its frame or - * no_focus_window; so this all needs rethinking massively. - * - * My suggestion is to change it so that we clearly separate - * actual keyboard focus tracking using the xterm algorithm, - * and mutter's "pretend" focus window, and go through all - * the code and decide which one should be used in each place; - * a hard bit is deciding on a policy for that. - * - * http://bugzilla.gnome.org/show_bug.cgi?id=90382 - */ - - /* We ignore grabs, though this is questionable. It may be better to - * increase the intelligence of the focus window tracking. - * - * The problem is that keybindings for windows are done with - * XGrabKey, which means focus_window disappears and the front of - * the MRU list gets confused from what the user expects once a - * keybinding is used. - */ - - if (event->mode == XINotifyGrab || - event->mode == XINotifyUngrab || - /* From WindowMaker, ignore all funky pointer root events */ - event->detail > XINotifyNonlinearVirtual) - { - meta_topic (META_DEBUG_FOCUS, - "Ignoring focus event generated by a grab or other weirdness\n"); - return; - } - - if (event->evtype == XI_FocusIn) - { - display->server_focus_window = event->event; - display->server_focus_serial = serial; - focus_window = window; - } - else if (event->evtype == XI_FocusOut) - { - if (event->detail == XINotifyInferior) - { - /* This event means the client moved focus to a subwindow */ - meta_topic (META_DEBUG_FOCUS, - "Ignoring focus out with NotifyInferior\n"); - return; - } - - display->server_focus_window = None; - display->server_focus_serial = serial; - focus_window = NULL; - } - else - g_return_if_reached (); - - /* If display->focused_by_us, then the focus_serial will be used only - * for a focus change we made and have already accounted for. - * (See request_xserver_input_focus_change().) Otherwise, we can get - * multiple focus events with the same serial. - */ - if (display->server_focus_serial > display->focus_serial || - (!display->focused_by_us && - display->server_focus_serial == display->focus_serial)) - { - update_focus_window (display, - focus_window, - focus_window ? focus_window->xwindow : None, - display->server_focus_serial, - FALSE); - } -} - -static gboolean -window_has_xwindow (MetaWindow *window, - Window xwindow) -{ - if (window->xwindow == xwindow) - return TRUE; - - if (window->frame && window->frame->xwindow == xwindow) - return TRUE; - - return FALSE; -} - -/** - * event_callback: - * @event: The event that just happened - * @data: The #MetaDisplay that events are coming from, cast to a gpointer - * so that it can be sent to a callback - * - * This is the most important function in the whole program. It is the heart, - * it is the nexus, it is the Grand Central Station of Mutter's world. - * When we create a #MetaDisplay, we ask GDK to pass *all* events for *all* - * windows to this function. So every time anything happens that we might - * want to know about, this function gets called. You see why it gets a bit - * busy around here. Most of this function is a ginormous switch statement - * dealing with all the kinds of events that might turn up. - */ -static gboolean -event_callback (XEvent *event, - gpointer data) -{ - MetaWindow *window; - MetaWindow *property_for_window; - MetaDisplay *display; - Window modified; - gboolean frame_was_receiver; - gboolean bypass_compositor; - gboolean filter_out_event; - XIEvent *input_event; - MetaMonitorManager *monitor; - MetaScreen *screen; - - display = data; - -#ifdef WITH_VERBOSE_MODE - if (dump_events) - meta_spew_event (display, event); -#endif - -#ifdef HAVE_STARTUP_NOTIFICATION - sn_display_process_event (display->sn_display, event); -#endif - - /* Intercept XRandR events early and don't attempt any - processing for them. We still let them through to Gdk though, - so it can update its own internal state. - */ - monitor = meta_monitor_manager_get (); - if (meta_monitor_manager_handle_xevent (monitor, event)) - return FALSE; - - bypass_compositor = FALSE; - filter_out_event = FALSE; - display->current_time = event_get_time (display, event); - display->monitor_cache_invalidated = TRUE; - - if (display->focused_by_us && - event->xany.serial > display->focus_serial && - display->focus_window && - !window_has_xwindow (display->focus_window, display->server_focus_window)) - { - meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed\n", - display->focus_window->desc); - update_focus_window (display, - meta_display_lookup_x_window (display, display->server_focus_window), - display->server_focus_window, - display->server_focus_serial, - FALSE); - } - - screen = meta_display_screen_for_root (display, event->xany.window); - if (screen) - { - if (meta_screen_handle_xevent (screen, event)) - return TRUE; - } - - modified = event_get_modified_window (display, event); - - input_event = get_input_event (display, event); - - if (event->type == UnmapNotify) - { - if (meta_ui_window_should_not_cause_focus (display->xdisplay, - modified)) - { - meta_display_add_ignored_crossing_serial (display, event->xany.serial); - meta_topic (META_DEBUG_FOCUS, - "Adding EnterNotify serial %lu to ignored focus serials\n", - event->xany.serial); - } - } - else if (input_event && - input_event->evtype == XI_Leave && - ((XILeaveEvent *)input_event)->mode == XINotifyUngrab && - modified == display->ungrab_should_not_cause_focus_window) - { - meta_display_add_ignored_crossing_serial (display, event->xany.serial); - meta_topic (META_DEBUG_FOCUS, - "Adding LeaveNotify serial %lu to ignored focus serials\n", - event->xany.serial); - } - - if (modified != None) - window = meta_display_lookup_x_window (display, modified); - else - window = NULL; - - /* We only want to respond to _NET_WM_USER_TIME property notify - * events on _NET_WM_USER_TIME_WINDOW windows; in particular, - * responding to UnmapNotify events is kind of bad. - */ - property_for_window = NULL; - if (window && modified == window->user_time_window) - { - property_for_window = window; - window = NULL; - } - - - frame_was_receiver = FALSE; - if (window && - window->frame && - modified == window->frame->xwindow) - { - /* Note that if the frame and the client both have an - * XGrabButton (as is normal with our setup), the event - * goes to the frame. - */ - frame_was_receiver = TRUE; - meta_topic (META_DEBUG_EVENTS, "Frame was receiver of event for %s\n", - window->desc); - } - -#ifdef HAVE_XSYNC - if (META_DISPLAY_HAS_XSYNC (display) && - event->type == (display->xsync_event_base + XSyncAlarmNotify)) - { - MetaWindow *alarm_window = meta_display_lookup_sync_alarm (display, - ((XSyncAlarmNotifyEvent*)event)->alarm); - - if (alarm_window != NULL) - { - XSyncValue value = ((XSyncAlarmNotifyEvent*)event)->counter_value; - gint64 new_counter_value; - new_counter_value = XSyncValueLow32 (value) + ((gint64)XSyncValueHigh32 (value) << 32); - meta_window_update_sync_request_counter (alarm_window, new_counter_value); - filter_out_event = TRUE; /* GTK doesn't want to see this really */ - } - else - meta_idle_monitor_handle_xevent_all (event); - } -#endif /* HAVE_XSYNC */ - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display) && - event->type == (display->shape_event_base + ShapeNotify)) - { - filter_out_event = TRUE; /* GTK doesn't want to see this really */ - - if (window && !frame_was_receiver) - { - XShapeEvent *sev = (XShapeEvent*) event; - - if (sev->kind == ShapeBounding) - meta_window_update_shape_region_x11 (window); - } - else - { - meta_topic (META_DEBUG_SHAPES, - "ShapeNotify not on a client window (window %s frame_was_receiver = %d)\n", - window ? window->desc : "(none)", - frame_was_receiver); - } - } -#endif /* HAVE_SHAPE */ - - if (input_event != NULL) - { - XIDeviceEvent *device_event = (XIDeviceEvent *) input_event; - XIEnterEvent *enter_event = (XIEnterEvent *) input_event; - gint button = 0; - - if (window && !window->override_redirect && - ((input_event->evtype == XI_KeyPress) || (input_event->evtype == XI_ButtonPress))) - { - if (CurrentTime == display->current_time) - { - /* We can't use missing (i.e. invalid) timestamps to set user time, - * nor do we want to use them to sanity check other timestamps. - * See bug 313490 for more details. - */ - meta_warning ("Event has no timestamp! You may be using a broken " - "program such as xse. Please ask the authors of that " - "program to fix it.\n"); - } - else - { - meta_window_set_user_time (window, display->current_time); - sanity_check_timestamps (display, display->current_time); - } - } - - switch (input_event->evtype) - { - case XI_KeyPress: - case XI_KeyRelease: - - /* For key events, it's important to enforce single-handling, or - * we can get into a confused state. So if a keybinding is - * handled (because it's one of our hot-keys, or because we are - * in a keyboard-grabbed mode like moving a window, we don't - * want to pass the key event to the compositor or GTK+ at all. - */ - if (meta_display_process_key_event (display, window, (XIDeviceEvent *) input_event)) - filter_out_event = bypass_compositor = TRUE; - break; - case XI_TouchBegin: - /* Filter out non-pointer-emulating touches */ - if ((((XIDeviceEvent *) input_event)->flags & XITouchEmulatingPointer) == 0) - break; - - /* Fall through */ - case XI_ButtonPress: - if (display->grab_op == META_GRAB_OP_COMPOSITOR) - break; - - display->overlay_key_only_pressed = FALSE; - - if (input_event->evtype == XI_ButtonPress) - { - if (device_event->detail == 4 || device_event->detail == 5) - /* Scrollwheel event, do nothing and deliver event to compositor below */ - break; - else - button = device_event->detail; - } - else if (input_event->evtype == XI_TouchBegin) - button = 1; - - if ((window && - meta_grab_op_is_mouse (display->grab_op) && - (device_event->mods.effective & display->window_grab_modifiers) && - display->grab_button != button && - display->grab_window == window) || - grab_op_is_keyboard (display->grab_op)) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Ending grab op %u on window %s due to button press\n", - display->grab_op, - (display->grab_window ? - display->grab_window->desc : - "none")); - meta_display_end_grab_op (display, - device_event->time); - } - else if (window && display->grab_op == META_GRAB_OP_NONE) - { - gboolean begin_move = FALSE; - unsigned int grab_mask; - gboolean unmodified; - - grab_mask = display->window_grab_modifiers; - if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS")) - grab_mask |= ControlMask; - - /* Two possible sources of an unmodified event; one is a - * client that's letting button presses pass through to the - * frame, the other is our focus_window_grab on unmodified - * button 1. So for all such events we focus the window. - */ - unmodified = (device_event->mods.effective & grab_mask) == 0; - - if (unmodified || button == 1) - { - /* don't focus if frame received, will be lowered in - * frames.c or special-cased if the click was on a - * minimize/close button. - */ - if (!frame_was_receiver) - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - else - meta_topic (META_DEBUG_FOCUS, - "Not raising window on click due to don't-raise-on-click option\n"); - - /* Don't focus panels--they must explicitly request focus. - * See bug 160470 - */ - if (window->type != META_WINDOW_DOCK) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing %s due to unmodified button %u press (display.c)\n", - window->desc, button); - meta_window_focus (window, device_event->time); - } - else - /* However, do allow terminals to lose focus due to new - * window mappings after the user clicks on a panel. - */ - display->allow_terminal_deactivation = TRUE; - } - - /* you can move on alt-click but not on - * the click-to-focus - */ - if (!unmodified) - begin_move = TRUE; - } - else if (!unmodified && button == meta_prefs_get_mouse_button_resize()) - { - if (window->has_resize_func) - { - gboolean north, south; - gboolean west, east; - MetaRectangle frame_rect; - MetaGrabOp op; - - meta_window_get_frame_rect (window, &frame_rect); - - west = device_event->root_x < (frame_rect.x + 1 * frame_rect.width / 3); - east = device_event->root_x > (frame_rect.x + 2 * frame_rect.width / 3); - north = device_event->root_y < (frame_rect.y + 1 * frame_rect.height / 3); - south = device_event->root_y > (frame_rect.y + 2 * frame_rect.height / 3); - - if (north && west) - op = META_GRAB_OP_RESIZING_NW; - else if (north && east) - op = META_GRAB_OP_RESIZING_NE; - else if (south && west) - op = META_GRAB_OP_RESIZING_SW; - else if (south && east) - op = META_GRAB_OP_RESIZING_SE; - else if (north) - op = META_GRAB_OP_RESIZING_N; - else if (west) - op = META_GRAB_OP_RESIZING_W; - else if (east) - op = META_GRAB_OP_RESIZING_E; - else if (south) - op = META_GRAB_OP_RESIZING_S; - else /* Middle region is no-op to avoid user triggering wrong action */ - op = META_GRAB_OP_NONE; - - if (op != META_GRAB_OP_NONE) - meta_display_begin_grab_op (display, - window->screen, - window, - op, - TRUE, - FALSE, - button, - 0, - device_event->time, - device_event->root_x, - device_event->root_y); - } - } - else if (button == meta_prefs_get_mouse_button_menu()) - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - meta_window_show_menu (window, - device_event->root_x, - device_event->root_y, - button, - device_event->time); - } - - if (!frame_was_receiver && unmodified) - { - /* This is from our synchronous grab since - * it has no modifiers and was on the client window - */ - - meta_verbose ("Allowing events time %u\n", - (unsigned int)device_event->time); - - XIAllowEvents (display->xdisplay, device_event->deviceid, - XIReplayDevice, device_event->time); - } - - if (begin_move && window->has_move_func) - { - meta_display_begin_grab_op (display, - window->screen, - window, - META_GRAB_OP_MOVING, - TRUE, - FALSE, - button, - 0, - device_event->time, - device_event->root_x, - device_event->root_y); - } - } - break; - case XI_ButtonRelease: - if (display->grab_op == META_GRAB_OP_COMPOSITOR) - break; - - display->overlay_key_only_pressed = FALSE; - - if (display->grab_window == window && - meta_grab_op_is_mouse (display->grab_op)) - meta_window_handle_mouse_grab_op_event (window, device_event); - break; - case XI_Motion: - if (display->grab_op == META_GRAB_OP_COMPOSITOR) - break; - - if (display->grab_window == window && - meta_grab_op_is_mouse (display->grab_op)) - meta_window_handle_mouse_grab_op_event (window, device_event); - break; - case XI_Enter: - if (display->grab_op == META_GRAB_OP_COMPOSITOR) - break; - - /* If the mouse switches screens, active the default window on the new - * screen; this will make keybindings and workspace-launched items - * actually appear on the right screen. - */ - { - MetaScreen *new_screen = - meta_display_screen_for_root (display, enter_event->root); - - if (new_screen != NULL && display->active_screen != new_screen) - meta_workspace_focus_default_window (new_screen->active_workspace, - NULL, - enter_event->time); - } - - /* Check if we've entered a window; do this even if window->has_focus to - * avoid races. - */ - if (window && !crossing_serial_is_ignored (display, event->xany.serial) && - enter_event->mode != XINotifyGrab && - enter_event->mode != XINotifyUngrab && - enter_event->detail != XINotifyInferior && - meta_display_focus_sentinel_clear (display)) - { - switch (meta_prefs_get_focus_mode ()) - { - case G_DESKTOP_FOCUS_MODE_SLOPPY: - case G_DESKTOP_FOCUS_MODE_MOUSE: - display->mouse_mode = TRUE; - if (window->type != META_WINDOW_DOCK) - { - meta_topic (META_DEBUG_FOCUS, - "Queuing a focus change for %s due to " - "enter notify with serial %lu at time %lu, " - "and setting display->mouse_mode to TRUE.\n", - window->desc, - event->xany.serial, - enter_event->time); - - if (meta_prefs_get_focus_change_on_pointer_rest()) - meta_display_queue_focus_callback (display, window, - enter_event->root_x, - enter_event->root_y); - else - meta_display_mouse_mode_focus (display, window, - enter_event->time); - - /* stop ignoring stuff */ - reset_ignored_crossing_serials (display); - } - break; - case G_DESKTOP_FOCUS_MODE_CLICK: - break; - } - - if (window->type == META_WINDOW_DOCK) - meta_window_raise (window); - } - break; - case XI_Leave: - if (display->grab_op == META_GRAB_OP_COMPOSITOR) - break; - - if (window != NULL) - { - if (window->type == META_WINDOW_DOCK && - enter_event->mode != XINotifyGrab && - enter_event->mode != XINotifyUngrab && - !window->has_focus) - meta_window_lower (window); - } - break; - case XI_FocusIn: - case XI_FocusOut: - /* libXi does not properly copy the serial to the XIEnterEvent, so pull it - * from the parent XAnyEvent. - * See: https://bugs.freedesktop.org/show_bug.cgi?id=64687 - */ - handle_window_focus_event (display, window, enter_event, event->xany.serial); - if (!window) - { - /* Check if the window is a root window. */ - MetaScreen *screen = - meta_display_screen_for_root(display, - enter_event->event); - if (screen == NULL) - break; - - if (enter_event->evtype == XI_FocusIn && - enter_event->mode == XINotifyDetailNone) - { - meta_topic (META_DEBUG_FOCUS, - "Focus got set to None, probably due to " - "brain-damage in the X protocol (see bug " - "125492). Setting the default focus window.\n"); - meta_workspace_focus_default_window (screen->active_workspace, - NULL, - meta_display_get_current_time_roundtrip (display)); - } - else if (enter_event->evtype == XI_FocusIn && - enter_event->mode == XINotifyNormal && - enter_event->detail == XINotifyInferior) - { - meta_topic (META_DEBUG_FOCUS, - "Focus got set to root window, probably due to " - "gnome-session logout dialog usage (see bug " - "153220). Setting the default focus window.\n"); - meta_workspace_focus_default_window (screen->active_workspace, - NULL, - meta_display_get_current_time_roundtrip (display)); - } - - } - break; -#ifdef HAVE_XI23 - case XI_BarrierHit: - case XI_BarrierLeave: - if (meta_display_process_barrier_event (display, (XIBarrierEvent *) input_event)) - filter_out_event = bypass_compositor = TRUE; - break; -#endif /* HAVE_XI23 */ - case XI_TouchUpdate: - case XI_TouchEnd: - /* Filter out non-pointer-emulating touches */ - if ((((XIDeviceEvent *) input_event)->flags & XITouchEmulatingPointer) == 0) - break; - - /* Currently unhandled, if any grab_op is started through XI_TouchBegin, - * the XIGrabDevice() evmask drops touch events, so only emulated - * XI_Motions and XI_ButtonRelease will follow. - */ - g_assert_not_reached (); - break; - } - } - else - { - switch (event->type) - { - case KeymapNotify: - break; - case Expose: - break; - case GraphicsExpose: - break; - case NoExpose: - break; - case VisibilityNotify: - break; - case CreateNotify: - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xcreatewindow.parent); - if (screen) - meta_stack_tracker_create_event (screen->stack_tracker, - &event->xcreatewindow); - } - break; - - case DestroyNotify: - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xdestroywindow.event); - if (screen) - meta_stack_tracker_destroy_event (screen->stack_tracker, - &event->xdestroywindow); - } - if (window) - { - /* FIXME: It sucks that DestroyNotify events don't come with - * a timestamp; could we do something better here? Maybe X - * will change one day? - */ - guint32 timestamp; - timestamp = meta_display_get_current_time_roundtrip (display); - - if (display->grab_op != META_GRAB_OP_NONE && - display->grab_window == window) - meta_display_end_grab_op (display, timestamp); - - if (frame_was_receiver) - { - meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n", - window->frame->xwindow); - meta_error_trap_push (display); - meta_window_destroy_frame (window->frame->window); - meta_error_trap_pop (display); - } - else - { - /* Unmanage destroyed window */ - meta_window_unmanage (window, timestamp); - window = NULL; - } - } - break; - case UnmapNotify: - if (window) - { - /* FIXME: It sucks that UnmapNotify events don't come with - * a timestamp; could we do something better here? Maybe X - * will change one day? - */ - guint32 timestamp; - timestamp = meta_display_get_current_time_roundtrip (display); - - if (display->grab_op != META_GRAB_OP_NONE && - display->grab_window == window && - window->frame == NULL) - meta_display_end_grab_op (display, timestamp); - - if (!frame_was_receiver) - { - if (window->unmaps_pending == 0) - { - meta_topic (META_DEBUG_WINDOW_STATE, - "Window %s withdrawn\n", - window->desc); - - /* Unmanage withdrawn window */ - window->withdrawn = TRUE; - meta_window_unmanage (window, timestamp); - window = NULL; - } - else - { - window->unmaps_pending -= 1; - meta_topic (META_DEBUG_WINDOW_STATE, - "Received pending unmap, %d now pending\n", - window->unmaps_pending); - } - } - } - break; - case MapNotify: - /* NB: override redirect windows wont cause a map request so we - * watch out for map notifies against any root windows too if a - * compositor is enabled: */ - if (display->compositor && window == NULL - && meta_display_screen_for_root (display, event->xmap.event)) - { - window = meta_window_new (display, event->xmap.window, - FALSE, META_COMP_EFFECT_CREATE); - } - break; - case MapRequest: - if (window == NULL) - { - window = meta_window_new (display, event->xmaprequest.window, - FALSE, META_COMP_EFFECT_CREATE); - } - /* if frame was receiver it's some malicious send event or something */ - else if (!frame_was_receiver && window) - { - meta_verbose ("MapRequest on %s mapped = %d minimized = %d\n", - window->desc, window->mapped, window->minimized); - if (window->minimized) - { - meta_window_unminimize (window); - if (window->workspace != window->screen->active_workspace) - { - meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n", - window->mapped, window->minimized); - meta_window_change_workspace (window, - window->screen->active_workspace); - } - } - } - break; - case ReparentNotify: - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xconfigure.event); - if (screen) - meta_stack_tracker_reparent_event (screen->stack_tracker, - &event->xreparent); - } - break; - case ConfigureNotify: - if (event->xconfigure.event != event->xconfigure.window) - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xconfigure.event); - if (screen) - meta_stack_tracker_configure_event (screen->stack_tracker, - &event->xconfigure); - } - - if (window && window->override_redirect) - meta_window_configure_notify (window, &event->xconfigure); - - break; - case ConfigureRequest: - /* This comment and code is found in both twm and fvwm */ - /* - * According to the July 27, 1988 ICCCM draft, we should ignore size and - * position fields in the WM_NORMAL_HINTS property when we map a window. - * Instead, we'll read the current geometry. Therefore, we should respond - * to configuration requests for windows which have never been mapped. - */ - if (window == NULL) - { - unsigned int xwcm; - XWindowChanges xwc; - - xwcm = event->xconfigurerequest.value_mask & - (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); - - xwc.x = event->xconfigurerequest.x; - xwc.y = event->xconfigurerequest.y; - xwc.width = event->xconfigurerequest.width; - xwc.height = event->xconfigurerequest.height; - xwc.border_width = event->xconfigurerequest.border_width; - - meta_verbose ("Configuring withdrawn window to %d,%d %dx%d border %d (some values may not be in mask)\n", - xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width); - meta_error_trap_push (display); - XConfigureWindow (display->xdisplay, event->xconfigurerequest.window, - xwcm, &xwc); - meta_error_trap_pop (display); - } - else - { - if (!frame_was_receiver) - meta_window_configure_request (window, event); - } - break; - case GravityNotify: - break; - case ResizeRequest: - break; - case CirculateNotify: - break; - case CirculateRequest: - break; - case PropertyNotify: - { - MetaGroup *group; - MetaScreen *screen; - - if (window && !frame_was_receiver) - meta_window_property_notify (window, event); - else if (property_for_window && !frame_was_receiver) - meta_window_property_notify (property_for_window, event); - - group = meta_display_lookup_group (display, - event->xproperty.window); - if (group != NULL) - meta_group_property_notify (group, event); - - screen = NULL; - if (window == NULL && - group == NULL) /* window/group != NULL means it wasn't a root window */ - screen = meta_display_screen_for_root (display, - event->xproperty.window); - - if (screen != NULL) - { - if (event->xproperty.atom == - display->atom__NET_DESKTOP_LAYOUT) - meta_screen_update_workspace_layout (screen); - else if (event->xproperty.atom == - display->atom__NET_DESKTOP_NAMES) - meta_screen_update_workspace_names (screen); -#if 0 - else if (event->xproperty.atom == - display->atom__NET_RESTACK_WINDOW) - handle_net_restack_window (display, event); -#endif - - /* we just use this property as a sentinel to avoid - * certain race conditions. See the comment for the - * sentinel_counter variable declaration in display.h - */ - if (event->xproperty.atom == - display->atom__MUTTER_SENTINEL) - { - meta_display_decrement_focus_sentinel (display); - } - } - } - break; - case SelectionClear: - /* do this here instead of at end of function - * so we can return - */ - - /* FIXME: Clearing display->current_time here makes no sense to - * me; who put this here and why? - */ - display->current_time = CurrentTime; - - process_selection_clear (display, event); - /* Note that processing that may have resulted in - * closing the display... so return right away. - */ - return FALSE; - case SelectionRequest: - process_selection_request (display, event); - break; - case SelectionNotify: - break; - case ColormapNotify: - if (window && !frame_was_receiver) - window->colormap = event->xcolormap.colormap; - break; - case ClientMessage: - if (window) - { - if (!frame_was_receiver) - meta_window_client_message (window, event); - } - else - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xclient.window); - - if (screen) - { - if (event->xclient.message_type == - display->atom__NET_CURRENT_DESKTOP) - { - int space; - MetaWorkspace *workspace; - guint32 time; - - space = event->xclient.data.l[0]; - time = event->xclient.data.l[1]; - - meta_verbose ("Request to change current workspace to %d with " - "specified timestamp of %u\n", - space, time); - - workspace = - meta_screen_get_workspace_by_index (screen, - space); - - /* Handle clients using the older version of the spec... */ - if (time == 0 && workspace) - { - meta_warning ("Received a NET_CURRENT_DESKTOP message " - "from a broken (outdated) client who sent " - "a 0 timestamp\n"); - time = meta_display_get_current_time_roundtrip (display); - } - - if (workspace) - meta_workspace_activate (workspace, time); - else - meta_verbose ("Don't know about workspace %d\n", space); - } - else if (event->xclient.message_type == - display->atom__NET_NUMBER_OF_DESKTOPS) - { - int num_spaces; - - num_spaces = event->xclient.data.l[0]; - - meta_verbose ("Request to set number of workspaces to %d\n", - num_spaces); - - meta_prefs_set_num_workspaces (num_spaces); - } - else if (event->xclient.message_type == - display->atom__NET_SHOWING_DESKTOP) - { - gboolean showing_desktop; - guint32 timestamp; - - showing_desktop = event->xclient.data.l[0] != 0; - /* FIXME: Braindead protocol doesn't have a timestamp */ - timestamp = meta_display_get_current_time_roundtrip (display); - meta_verbose ("Request to %s desktop\n", - showing_desktop ? "show" : "hide"); - - if (showing_desktop) - meta_screen_show_desktop (screen, timestamp); - else - { - meta_screen_unshow_desktop (screen); - meta_workspace_focus_default_window (screen->active_workspace, NULL, timestamp); - } - } - else if (event->xclient.message_type == - display->atom_WM_PROTOCOLS) - { - meta_verbose ("Received WM_PROTOCOLS message\n"); - - if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING) - { - process_pong_message (display, event); - - /* We don't want ping reply events going into - * the GTK+ event loop because gtk+ will treat - * them as ping requests and send more replies. - */ - filter_out_event = TRUE; - } - } - } - - if (event->xclient.message_type == - display->atom__NET_REQUEST_FRAME_EXTENTS) - { - meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message\n"); - process_request_frame_extents (display, event); - } - } - break; - case MappingNotify: - { - gboolean ignore_current; - - ignore_current = FALSE; - - /* Check whether the next event is an identical MappingNotify - * event. If it is, ignore the current event, we'll update - * when we get the next one. - */ - if (XPending (display->xdisplay)) - { - XEvent next_event; - - XPeekEvent (display->xdisplay, &next_event); - - if (next_event.type == MappingNotify && - next_event.xmapping.request == event->xmapping.request) - ignore_current = TRUE; - } - - if (!ignore_current) - { - /* Let XLib know that there is a new keyboard mapping. - */ - XRefreshKeyboardMapping (&event->xmapping); - meta_display_process_mapping_event (display, event); - } - } - break; - default: -#ifdef HAVE_XKB - if (event->type == display->xkb_base_event_type) - { - XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event; - - switch (xkb_ev->xkb_type) - { - case XkbBellNotify: - if (XSERVER_TIME_IS_BEFORE(display->last_bell_time, - xkb_ev->time - 100)) - { - display->last_bell_time = xkb_ev->time; - meta_bell_notify (display, xkb_ev); - } - break; - case XkbNewKeyboardNotify: - case XkbMapNotify: - if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID) - meta_display_process_mapping_event (display, event); - break; - } - } -#endif - break; - } - } - - if (display->compositor && !bypass_compositor) - { - if (meta_compositor_process_event (display->compositor, - event, - window)) - filter_out_event = TRUE; - } - - display->current_time = CurrentTime; - return filter_out_event; -} - -/* Return the window this has to do with, if any, rather - * than the frame or root window that was selecting - * for substructure - */ -static Window -event_get_modified_window (MetaDisplay *display, - XEvent *event) -{ - XIEvent *input_event = get_input_event (display, event); - - if (input_event) - { - switch (input_event->evtype) - { - case XI_Motion: - case XI_ButtonPress: - case XI_ButtonRelease: - case XI_KeyPress: - case XI_KeyRelease: - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: - return ((XIDeviceEvent *) input_event)->event; - case XI_FocusIn: - case XI_FocusOut: - case XI_Enter: - case XI_Leave: - return ((XIEnterEvent *) input_event)->event; -#ifdef HAVE_XI23 - case XI_BarrierHit: - case XI_BarrierLeave: - return ((XIBarrierEvent *) input_event)->event; -#endif /* HAVE_XI23 */ - } - } - - switch (event->type) - { - case KeymapNotify: - case Expose: - case GraphicsExpose: - case NoExpose: - case VisibilityNotify: - case ResizeRequest: - case PropertyNotify: - case SelectionClear: - case SelectionRequest: - case SelectionNotify: - case ColormapNotify: - case ClientMessage: - return event->xany.window; - - case CreateNotify: - return event->xcreatewindow.window; - - case DestroyNotify: - return event->xdestroywindow.window; - - case UnmapNotify: - return event->xunmap.window; - - case MapNotify: - return event->xmap.window; - - case MapRequest: - return event->xmaprequest.window; - - case ReparentNotify: - return event->xreparent.window; - - case ConfigureNotify: - return event->xconfigure.window; - - case ConfigureRequest: - return event->xconfigurerequest.window; - - case GravityNotify: - return event->xgravity.window; - - case CirculateNotify: - return event->xcirculate.window; - - case CirculateRequest: - return event->xcirculaterequest.window; - - case MappingNotify: - return None; - - default: -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display) && - event->type == (display->shape_event_base + ShapeNotify)) - { - XShapeEvent *sev = (XShapeEvent*) event; - return sev->window; - } -#endif - - return None; - } -} - -static guint32 -event_get_time (MetaDisplay *display, - XEvent *event) -{ - XIEvent *input_event = get_input_event (display, event); - - if (input_event) - return input_event->time; - - switch (event->type) - { - case PropertyNotify: - return event->xproperty.time; - - case SelectionClear: - case SelectionRequest: - case SelectionNotify: - return event->xselection.time; - - case KeymapNotify: - case Expose: - case GraphicsExpose: - case NoExpose: - case MapNotify: - case UnmapNotify: - case VisibilityNotify: - case ResizeRequest: - case ColormapNotify: - case ClientMessage: - case CreateNotify: - case DestroyNotify: - case MapRequest: - case ReparentNotify: - case ConfigureNotify: - case ConfigureRequest: - case GravityNotify: - case CirculateNotify: - case CirculateRequest: - case MappingNotify: - default: - return CurrentTime; - } -} - -#ifdef WITH_VERBOSE_MODE -const char* -meta_event_detail_to_string (int d) -{ - const char *detail = "???"; - switch (d) - { - /* We are an ancestor in the A<->B focus change relationship */ - case XINotifyAncestor: - detail = "NotifyAncestor"; - break; - case XINotifyDetailNone: - detail = "NotifyDetailNone"; - break; - /* We are a descendant in the A<->B focus change relationship */ - case XINotifyInferior: - detail = "NotifyInferior"; - break; - case XINotifyNonlinear: - detail = "NotifyNonlinear"; - break; - case XINotifyNonlinearVirtual: - detail = "NotifyNonlinearVirtual"; - break; - case XINotifyPointer: - detail = "NotifyPointer"; - break; - case XINotifyPointerRoot: - detail = "NotifyPointerRoot"; - break; - case XINotifyVirtual: - detail = "NotifyVirtual"; - break; - } - - return detail; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef WITH_VERBOSE_MODE -const char* -meta_event_mode_to_string (int m) -{ - const char *mode = "???"; - switch (m) - { - case XINotifyNormal: - mode = "NotifyNormal"; - break; - case XINotifyGrab: - mode = "NotifyGrab"; - break; - case XINotifyUngrab: - mode = "NotifyUngrab"; - break; - case XINotifyWhileGrabbed: - mode = "NotifyWhileGrabbed"; - break; - } - - return mode; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef WITH_VERBOSE_MODE -static const char* -stack_mode_to_string (int mode) -{ - switch (mode) - { - case Above: - return "Above"; - case Below: - return "Below"; - case TopIf: - return "TopIf"; - case BottomIf: - return "BottomIf"; - case Opposite: - return "Opposite"; - } - - return "Unknown"; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef HAVE_XSYNC -#ifdef WITH_VERBOSE_MODE -static gint64 -sync_value_to_64 (const XSyncValue *value) -{ - gint64 v; - - v = XSyncValueLow32 (*value); - v |= (((gint64)XSyncValueHigh32 (*value)) << 32); - - return v; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef WITH_VERBOSE_MODE -static const char* -alarm_state_to_string (XSyncAlarmState state) -{ - switch (state) - { - case XSyncAlarmActive: - return "Active"; - case XSyncAlarmInactive: - return "Inactive"; - case XSyncAlarmDestroyed: - return "Destroyed"; - default: - return "(unknown)"; - } -} -#endif /* WITH_VERBOSE_MODE */ - -#endif /* HAVE_XSYNC */ - -#ifdef WITH_VERBOSE_MODE -static void -meta_spew_xi2_event (MetaDisplay *display, - XIEvent *input_event, - const char **name_p, - char **extra_p) -{ - const char *name = NULL; - char *extra = NULL; - - XIDeviceEvent *device_event = (XIDeviceEvent *) input_event; - XIEnterEvent *enter_event = (XIEnterEvent *) input_event; - - switch (input_event->evtype) - { - case XI_Motion: - name = "XI_Motion"; - break; - case XI_ButtonPress: - name = "XI_ButtonPress"; - break; - case XI_ButtonRelease: - name = "XI_ButtonRelease"; - break; - case XI_KeyPress: - name = "XI_KeyPress"; - break; - case XI_KeyRelease: - name = "XI_KeyRelease"; - break; - case XI_FocusIn: - name = "XI_FocusIn"; - break; - case XI_FocusOut: - name = "XI_FocusOut"; - break; - case XI_Enter: - name = "XI_Enter"; - break; - case XI_Leave: - name = "XI_Leave"; - break; - case XI_TouchBegin: - name = "XI_TouchBegin"; - break; - case XI_TouchUpdate: - name = "XI_TouchUpdate"; - break; - case XI_TouchEnd: - name = "XI_TouchEnd"; - break; -#ifdef HAVE_XI23 - case XI_BarrierHit: - name = "XI_BarrierHit"; - break; - case XI_BarrierLeave: - name = "XI_BarrierLeave"; - break; -#endif /* HAVE_XI23 */ - } - - switch (input_event->evtype) - { - case XI_Motion: - extra = g_strdup_printf ("win: 0x%lx x: %g y: %g", - device_event->event, - device_event->root_x, - device_event->root_y); - break; - case XI_ButtonPress: - case XI_ButtonRelease: - extra = g_strdup_printf ("button %u x %g y %g root 0x%lx", - device_event->detail, - device_event->root_x, - device_event->root_y, - device_event->root); - break; - case XI_KeyPress: - case XI_KeyRelease: - { - KeySym keysym; - const char *str; - - keysym = XKeycodeToKeysym (display->xdisplay, device_event->detail, 0); - - str = XKeysymToString (keysym); - - extra = g_strdup_printf ("Key '%s' state 0x%x", - str ? str : "none", device_event->mods.effective); - } - break; - case XI_FocusIn: - case XI_FocusOut: - extra = g_strdup_printf ("detail: %s mode: %s\n", - meta_event_detail_to_string (enter_event->detail), - meta_event_mode_to_string (enter_event->mode)); - break; - case XI_Enter: - case XI_Leave: - extra = g_strdup_printf ("win: 0x%lx root: 0x%lx mode: %s detail: %s focus: %d x: %g y: %g", - enter_event->event, - enter_event->root, - meta_event_mode_to_string (enter_event->mode), - meta_event_detail_to_string (enter_event->detail), - enter_event->focus, - enter_event->root_x, - enter_event->root_y); - break; - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: - extra = g_strdup_printf ("win: 0x%lx root: 0x%lx touch sequence: %d x: %g y: %g state: 0x%x flags: 0x%x", - device_event->event, - device_event->root, - device_event->detail, - device_event->root_x, - device_event->root_y, - device_event->mods.effective, - device_event->flags); - break; - } - - *name_p = name; - *extra_p = extra; -} - -static void -meta_spew_core_event (MetaDisplay *display, - XEvent *event, - const char **name_p, - char **extra_p) -{ - const char *name = NULL; - char *extra = NULL; - - switch (event->type) - { - case KeymapNotify: - name = "KeymapNotify"; - break; - case Expose: - name = "Expose"; - break; - case GraphicsExpose: - name = "GraphicsExpose"; - break; - case NoExpose: - name = "NoExpose"; - break; - case VisibilityNotify: - name = "VisibilityNotify"; - break; - case CreateNotify: - name = "CreateNotify"; - extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx", - event->xcreatewindow.parent, - event->xcreatewindow.window); - break; - case DestroyNotify: - name = "DestroyNotify"; - extra = g_strdup_printf ("event: 0x%lx window: 0x%lx", - event->xdestroywindow.event, - event->xdestroywindow.window); - break; - case UnmapNotify: - name = "UnmapNotify"; - extra = g_strdup_printf ("event: 0x%lx window: 0x%lx from_configure: %d", - event->xunmap.event, - event->xunmap.window, - event->xunmap.from_configure); - break; - case MapNotify: - name = "MapNotify"; - extra = g_strdup_printf ("event: 0x%lx window: 0x%lx override_redirect: %d", - event->xmap.event, - event->xmap.window, - event->xmap.override_redirect); - break; - case MapRequest: - name = "MapRequest"; - extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n", - event->xmaprequest.window, - event->xmaprequest.parent); - break; - case ReparentNotify: - name = "ReparentNotify"; - extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx event: 0x%lx\n", - event->xreparent.window, - event->xreparent.parent, - event->xreparent.event); - break; - case ConfigureNotify: - name = "ConfigureNotify"; - extra = g_strdup_printf ("x: %d y: %d w: %d h: %d above: 0x%lx override_redirect: %d", - event->xconfigure.x, - event->xconfigure.y, - event->xconfigure.width, - event->xconfigure.height, - event->xconfigure.above, - event->xconfigure.override_redirect); - break; - case ConfigureRequest: - name = "ConfigureRequest"; - extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx x: %d %sy: %d %sw: %d %sh: %d %sborder: %d %sabove: %lx %sstackmode: %s %s", - event->xconfigurerequest.parent, - event->xconfigurerequest.window, - event->xconfigurerequest.x, - event->xconfigurerequest.value_mask & - CWX ? "" : "(unset) ", - event->xconfigurerequest.y, - event->xconfigurerequest.value_mask & - CWY ? "" : "(unset) ", - event->xconfigurerequest.width, - event->xconfigurerequest.value_mask & - CWWidth ? "" : "(unset) ", - event->xconfigurerequest.height, - event->xconfigurerequest.value_mask & - CWHeight ? "" : "(unset) ", - event->xconfigurerequest.border_width, - event->xconfigurerequest.value_mask & - CWBorderWidth ? "" : "(unset)", - event->xconfigurerequest.above, - event->xconfigurerequest.value_mask & - CWSibling ? "" : "(unset)", - stack_mode_to_string (event->xconfigurerequest.detail), - event->xconfigurerequest.value_mask & - CWStackMode ? "" : "(unset)"); - break; - case GravityNotify: - name = "GravityNotify"; - break; - case ResizeRequest: - name = "ResizeRequest"; - extra = g_strdup_printf ("width = %d height = %d", - event->xresizerequest.width, - event->xresizerequest.height); - break; - case CirculateNotify: - name = "CirculateNotify"; - break; - case CirculateRequest: - name = "CirculateRequest"; - break; - case PropertyNotify: - { - char *str; - const char *state; - - name = "PropertyNotify"; - - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xproperty.atom); - meta_error_trap_pop (display); - - if (event->xproperty.state == PropertyNewValue) - state = "PropertyNewValue"; - else if (event->xproperty.state == PropertyDelete) - state = "PropertyDelete"; - else - state = "???"; - - extra = g_strdup_printf ("atom: %s state: %s", - str ? str : "(unknown atom)", - state); - meta_XFree (str); - } - break; - case SelectionClear: - name = "SelectionClear"; - break; - case SelectionRequest: - name = "SelectionRequest"; - break; - case SelectionNotify: - name = "SelectionNotify"; - break; - case ColormapNotify: - name = "ColormapNotify"; - break; - case ClientMessage: - { - char *str; - name = "ClientMessage"; - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xclient.message_type); - meta_error_trap_pop (display); - extra = g_strdup_printf ("type: %s format: %d\n", - str ? str : "(unknown atom)", - event->xclient.format); - meta_XFree (str); - } - break; - case MappingNotify: - name = "MappingNotify"; - break; - default: -#ifdef HAVE_XSYNC - if (META_DISPLAY_HAS_XSYNC (display) && - event->type == (display->xsync_event_base + XSyncAlarmNotify)) - { - XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event; - - name = "XSyncAlarmNotify"; - extra = - g_strdup_printf ("alarm: 0x%lx" - " counter_value: %" G_GINT64_FORMAT - " alarm_value: %" G_GINT64_FORMAT - " time: %u alarm state: %s", - aevent->alarm, - (gint64) sync_value_to_64 (&aevent->counter_value), - (gint64) sync_value_to_64 (&aevent->alarm_value), - (unsigned int)aevent->time, - alarm_state_to_string (aevent->state)); - } - else -#endif /* HAVE_XSYNC */ -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display) && - event->type == (display->shape_event_base + ShapeNotify)) - { - XShapeEvent *sev = (XShapeEvent*) event; - - name = "ShapeNotify"; - - extra = - g_strdup_printf ("kind: %s " - "x: %d y: %d w: %u h: %u " - "shaped: %d", - sev->kind == ShapeBounding ? - "ShapeBounding" : - (sev->kind == ShapeClip ? - "ShapeClip" : "(unknown)"), - sev->x, sev->y, sev->width, sev->height, - sev->shaped); - } - else -#endif /* HAVE_SHAPE */ - { - name = "(Unknown event)"; - extra = g_strdup_printf ("type: %d", event->xany.type); - } - break; - } - - *name_p = name; - *extra_p = extra; -} - -static void -meta_spew_event (MetaDisplay *display, - XEvent *event) -{ - const char *name = NULL; - char *extra = NULL; - char *winname; - MetaScreen *screen; - XIEvent *input_event; - - if (!meta_is_verbose()) - return; - - /* filter overnumerous events */ - if (event->type == Expose || event->type == MotionNotify || - event->type == NoExpose) - return; - - if (event->type == (display->damage_event_base + XDamageNotify)) - return; - - if (event->type == (display->xsync_event_base + XSyncAlarmNotify)) - return; - - if (event->type == PropertyNotify && event->xproperty.atom == display->atom__NET_WM_USER_TIME) - return; - - input_event = get_input_event (display, event); - - if (input_event) - meta_spew_xi2_event (display, input_event, &name, &extra); - else - meta_spew_core_event (display, event, &name, &extra); - - screen = meta_display_screen_for_root (display, event->xany.window); - - if (screen) - winname = g_strdup_printf ("root %d", screen->number); - else - winname = g_strdup_printf ("0x%lx", event->xany.window); - - meta_topic (META_DEBUG_EVENTS, - "%s on %s%s %s %sserial %lu\n", name, winname, - extra ? ":" : "", extra ? extra : "", - event->xany.send_event ? "SEND " : "", - event->xany.serial); - - g_free (winname); - - if (extra) - g_free (extra); -} -#endif /* WITH_VERBOSE_MODE */ - MetaWindow* meta_display_lookup_x_window (MetaDisplay *display, Window xwindow) @@ -3823,6 +1691,20 @@ meta_display_unregister_x_window (MetaDisplay *display, remove_pending_pings_for_window (display, xwindow); } +void +meta_display_register_wayland_window (MetaDisplay *display, + MetaWindow *window) +{ + g_hash_table_add (display->wayland_windows, window); +} + +void +meta_display_unregister_wayland_window (MetaDisplay *display, + MetaWindow *window) +{ + g_hash_table_remove (display->wayland_windows, window); +} + #ifdef HAVE_XSYNC /* We store sync alarms in the window ID hash table, because they are * just more types of XIDs in the same global space, but we have @@ -3876,73 +1758,56 @@ gboolean meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display, Window xwindow) { - gboolean is_a_no_focus_window = FALSE; - GSList *temp = display->screens; - while (temp != NULL) { - MetaScreen *screen = temp->data; - if (screen->no_focus_window == xwindow) { - is_a_no_focus_window = TRUE; - break; - } - temp = temp->next; - } - - return is_a_no_focus_window; + return xwindow == display->screen->no_focus_window; } -static Cursor -xcursor_for_op (MetaDisplay *display, - MetaGrabOp op) +static MetaCursor +meta_cursor_for_grab_op (MetaGrabOp op) { - MetaCursor cursor = META_CURSOR_DEFAULT; - switch (op) { case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_SE: - cursor = META_CURSOR_SE_RESIZE; + return META_CURSOR_SE_RESIZE; break; case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_S: - cursor = META_CURSOR_SOUTH_RESIZE; + return META_CURSOR_SOUTH_RESIZE; break; case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_SW: - cursor = META_CURSOR_SW_RESIZE; + return META_CURSOR_SW_RESIZE; break; case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_N: - cursor = META_CURSOR_NORTH_RESIZE; + return META_CURSOR_NORTH_RESIZE; break; case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: - cursor = META_CURSOR_NE_RESIZE; + return META_CURSOR_NE_RESIZE; break; case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: - cursor = META_CURSOR_NW_RESIZE; + return META_CURSOR_NW_RESIZE; break; case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_W: - cursor = META_CURSOR_WEST_RESIZE; + return META_CURSOR_WEST_RESIZE; break; case META_GRAB_OP_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_E: - cursor = META_CURSOR_EAST_RESIZE; + return META_CURSOR_EAST_RESIZE; break; case META_GRAB_OP_MOVING: case META_GRAB_OP_KEYBOARD_MOVING: case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: - cursor = META_CURSOR_MOVE_OR_RESIZE_WINDOW; + return META_CURSOR_MOVE_OR_RESIZE_WINDOW; break; - default: break; } - if (cursor == META_CURSOR_DEFAULT) - return None; - return meta_display_create_x_cursor (display, cursor); + return META_CURSOR_DEFAULT; } void @@ -3952,9 +1817,10 @@ meta_display_set_grab_op_cursor (MetaDisplay *display, Window grab_xwindow, guint32 timestamp) { - Cursor cursor = xcursor_for_op (display, op); unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; + MetaCursor cursor = meta_cursor_for_grab_op (op); + MetaCursorReference *cursor_ref; XISetMask (mask.mask, XI_ButtonPress); XISetMask (mask.mask, XI_ButtonRelease); @@ -3969,7 +1835,7 @@ meta_display_set_grab_op_cursor (MetaDisplay *display, META_VIRTUAL_CORE_POINTER_ID, grab_xwindow, timestamp, - cursor, + meta_display_create_x_cursor (display, cursor), XIGrabModeAsync, XIGrabModeAsync, False, /* owner_events */ &mask) == Success) @@ -3985,10 +1851,12 @@ meta_display_set_grab_op_cursor (MetaDisplay *display, "XIGrabDevice() failed time %u\n", timestamp); } + meta_error_trap_pop (display); - - if (cursor != None) - XFreeCursor (display->xdisplay, cursor); + + cursor_ref = meta_cursor_reference_from_theme (screen->cursor_tracker, cursor); + meta_cursor_tracker_set_grab_cursor (screen->cursor_tracker, cursor_ref); + meta_cursor_reference_unref (cursor_ref); } gboolean @@ -3999,7 +1867,7 @@ meta_display_begin_grab_op (MetaDisplay *display, gboolean pointer_already_grabbed, gboolean frame_action, int button, - gulong modmask, + gulong modmask, /* XXX - ignored */ guint32 timestamp, int root_x, int root_y) @@ -4062,7 +1930,7 @@ meta_display_begin_grab_op (MetaDisplay *display, meta_display_set_grab_op_cursor (display, screen, op, grab_xwindow, timestamp); - if (!display->grab_have_pointer && !grab_op_is_keyboard (op)) + if (!display->grab_have_pointer && !meta_grab_op_is_keyboard (op)) { meta_topic (META_DEBUG_WINDOW_OPS, "XIGrabDevice() failed\n"); @@ -4070,7 +1938,7 @@ meta_display_begin_grab_op (MetaDisplay *display, } /* Grab keys for keyboard ops and mouse move/resizes; see #126497 */ - if (grab_op_is_keyboard (op) || grab_op_is_mouse_only (op)) + if (meta_grab_op_is_keyboard (op) || grab_op_is_mouse_only (op)) { if (grab_window) display->grab_have_keyboard = @@ -4092,10 +1960,8 @@ meta_display_begin_grab_op (MetaDisplay *display, display->grab_op = op; display->grab_window = grab_window; - display->grab_screen = screen; display->grab_xwindow = grab_xwindow; display->grab_button = button; - display->grab_mask = modmask; if (window) { display->grab_tile_mode = window->tile_mode; @@ -4112,7 +1978,6 @@ meta_display_begin_grab_op (MetaDisplay *display, display->grab_latest_motion_y = root_y; display->grab_last_moveresize_time.tv_sec = 0; display->grab_last_moveresize_time.tv_usec = 0; - display->grab_motion_notify_time = 0; display->grab_old_window_stacking = NULL; #ifdef HAVE_XSYNC display->grab_last_user_action_was_snap = FALSE; @@ -4146,7 +2011,7 @@ meta_display_begin_grab_op (MetaDisplay *display, "Grab op %u on window %s successful\n", display->grab_op, window ? window->desc : "(null)"); - g_assert (display->grab_window != NULL || display->grab_screen != NULL); + g_assert (display->grab_window != NULL); g_assert (display->grab_op != META_GRAB_OP_NONE); if (display->grab_window) @@ -4154,6 +2019,9 @@ meta_display_begin_grab_op (MetaDisplay *display, meta_window_refresh_resize_popup (display->grab_window); } + if (meta_is_wayland_compositor ()) + meta_display_sync_wayland_input_focus (display); + g_signal_emit (display, display_signals[GRAB_OP_BEGIN], 0, screen, display->grab_window, display->grab_op); @@ -4171,7 +2039,7 @@ meta_display_end_grab_op (MetaDisplay *display, return; g_signal_emit (display, display_signals[GRAB_OP_END], 0, - display->grab_screen, display->grab_window, display->grab_op); + display->screen, display->grab_window, display->grab_op); if (display->grab_window != NULL) display->grab_window->shaken_loose = FALSE; @@ -4223,13 +2091,13 @@ meta_display_end_grab_op (MetaDisplay *display, if (display->grab_window) meta_window_ungrab_all_keys (display->grab_window, timestamp); else - meta_screen_ungrab_all_keys (display->grab_screen, timestamp); + meta_screen_ungrab_all_keys (display->screen, timestamp); } - + meta_cursor_tracker_set_grab_cursor (display->screen->cursor_tracker, NULL); + display->grab_timestamp = 0; display->grab_window = NULL; - display->grab_screen = NULL; display->grab_xwindow = None; display->grab_tile_mode = META_TILE_NONE; display->grab_tile_monitor_number = -1; @@ -4246,6 +2114,9 @@ meta_display_end_grab_op (MetaDisplay *display, g_source_remove (display->grab_resize_timeout_id); display->grab_resize_timeout_id = 0; } + + if (meta_is_wayland_compositor ()) + meta_display_sync_wayland_input_focus (display); } /** @@ -4321,7 +2192,7 @@ meta_change_button_grab (MetaDisplay *display, mods = (XIGrabModifiers) { modmask | ignored_mask, 0 }; if (meta_is_debugging ()) - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); /* GrabModeSync means freeze until XAllowEvents */ @@ -4516,30 +2387,19 @@ meta_display_increment_event_serial (MetaDisplay *display) void meta_display_update_active_window_hint (MetaDisplay *display) { - GSList *tmp; - gulong data[1]; if (display->focus_window) data[0] = display->focus_window->xwindow; else data[0] = None; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, screen->xroot, - display->atom__NET_ACTIVE_WINDOW, - XA_WINDOW, - 32, PropModeReplace, (guchar*) data, 1); - - meta_error_trap_pop (display); - tmp = tmp->next; - } + meta_error_trap_push (display); + XChangeProperty (display->xdisplay, display->screen->xroot, + display->atom__NET_ACTIVE_WINDOW, + XA_WINDOW, + 32, PropModeReplace, (guchar*) data, 1); + meta_error_trap_pop (display); } void @@ -4577,25 +2437,12 @@ void meta_display_set_cursor_theme (const char *theme, int size) { -#ifdef HAVE_XCURSOR - GSList *tmp; - MetaDisplay *display = meta_get_display (); XcursorSetTheme (display->xdisplay, theme); XcursorSetDefaultSize (display->xdisplay, size); - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_screen_update_cursor (screen); - - tmp = tmp->next; - } - -#endif + meta_screen_update_cursor (display->screen); } /* @@ -4662,24 +2509,20 @@ meta_set_syncing (gboolean setting) static gboolean meta_display_ping_timeout (gpointer data) { - MetaPingData *ping_data; - - ping_data = data; + MetaPingData *ping_data = data; + MetaDisplay *display = ping_data->window->display; ping_data->ping_timeout_id = 0; meta_topic (META_DEBUG_PING, - "Ping %u on window %lx timed out\n", - ping_data->timestamp, ping_data->xwindow); - - (* ping_data->ping_timeout_func) (ping_data->display, ping_data->xwindow, - ping_data->timestamp, ping_data->user_data); + "Ping %u on window %s timed out\n", + ping_data->timestamp, ping_data->window->desc); - ping_data->display->pending_pings = - g_slist_remove (ping_data->display->pending_pings, - ping_data); + (* ping_data->ping_timeout_func) (ping_data->window, ping_data->timestamp, ping_data->user_data); + + display->pending_pings = g_slist_remove (display->pending_pings, ping_data); ping_data_free (ping_data); - + return FALSE; } @@ -4703,19 +2546,15 @@ meta_display_ping_timeout (gpointer data) * we call the "got a response" callback immediately and return. * This function returns straight away after setting things up; * the callbacks will be called from the event loop. - * - * FIXME: This should probably be a method on windows, rather than displays - * for one of their windows. - * */ void -meta_display_ping_window (MetaDisplay *display, - MetaWindow *window, +meta_display_ping_window (MetaWindow *window, guint32 timestamp, MetaWindowPingFunc ping_reply_func, MetaWindowPingFunc ping_timeout_func, gpointer user_data) { + MetaDisplay *display = window->display; MetaPingData *ping_data; if (timestamp == CurrentTime) @@ -4724,17 +2563,16 @@ meta_display_ping_window (MetaDisplay *display, return; } - if (!window->net_wm_ping) + if (!window->can_ping) { if (ping_reply_func) - (* ping_reply_func) (display, window->xwindow, timestamp, user_data); + (* ping_reply_func) (window, timestamp, user_data); return; } - + ping_data = g_new (MetaPingData, 1); - ping_data->display = display; - ping_data->xwindow = window->xwindow; + ping_data->window = window; ping_data->timestamp = timestamp; ping_data->ping_reply_func = ping_reply_func; ping_data->ping_timeout_func = ping_timeout_func; @@ -4742,106 +2580,41 @@ meta_display_ping_window (MetaDisplay *display, ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY, meta_display_ping_timeout, ping_data); - + display->pending_pings = g_slist_prepend (display->pending_pings, ping_data); meta_topic (META_DEBUG_PING, "Sending ping with timestamp %u to window %s\n", timestamp, window->desc); - meta_window_send_icccm_message (window, - display->atom__NET_WM_PING, - timestamp); -} - -static void -process_request_frame_extents (MetaDisplay *display, - XEvent *event) -{ - /* The X window whose frame extents will be set. */ - Window xwindow = event->xclient.window; - unsigned long data[4] = { 0, 0, 0, 0 }; - - MotifWmHints *hints = NULL; - gboolean hints_set = FALSE; - - meta_verbose ("Setting frame extents for 0x%lx\n", xwindow); - - /* See if the window is decorated. */ - hints_set = meta_prop_get_motif_hints (display, - xwindow, - display->atom__MOTIF_WM_HINTS, - &hints); - if ((hints_set && hints->decorations) || !hints_set) - { - MetaFrameBorders borders; - MetaScreen *screen; - - screen = meta_display_screen_for_xwindow (display, - event->xclient.window); - if (screen == NULL) - { - meta_warning ("Received request to set _NET_FRAME_EXTENTS " - "on 0x%lx which is on a screen we are not managing\n", - event->xclient.window); - meta_XFree (hints); - return; - } - - /* Return estimated frame extents for a normal window. */ - meta_ui_theme_get_frame_borders (screen->ui, - META_FRAME_TYPE_NORMAL, - 0, - &borders); - data[0] = borders.visible.left; - data[1] = borders.visible.right; - data[2] = borders.visible.top; - data[3] = borders.visible.bottom; - } - - meta_topic (META_DEBUG_GEOMETRY, - "Setting _NET_FRAME_EXTENTS on unmanaged window 0x%lx " - "to top = %lu, left = %lu, bottom = %lu, right = %lu\n", - xwindow, data[0], data[1], data[2], data[3]); - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, xwindow, - display->atom__NET_FRAME_EXTENTS, - XA_CARDINAL, - 32, PropModeReplace, (guchar*) data, 4); - meta_error_trap_pop (display); - meta_XFree (hints); + META_WINDOW_GET_CLASS (window)->ping (window, timestamp); } /** - * process_pong_message: + * meta_display_pong_for_serial: * @display: the display we got the pong from - * @event: the #XEvent which is a pong; we can tell which - * ping it corresponds to because it bears the - * same timestamp. + * @serial: the serial in the pong repsonse * * Process the pong (the response message) from the ping we sent * to the window. This involves removing the timeout, calling the * reply handler function, and freeing memory. */ -static void -process_pong_message (MetaDisplay *display, - XEvent *event) +void +meta_display_pong_for_serial (MetaDisplay *display, + guint32 serial) { GSList *tmp; - guint32 timestamp = event->xclient.data.l[1]; - meta_topic (META_DEBUG_PING, "Received a pong with timestamp %u\n", - timestamp); - + meta_topic (META_DEBUG_PING, "Received a pong with serial %u\n", serial); + for (tmp = display->pending_pings; tmp; tmp = tmp->next) { MetaPingData *ping_data = tmp->data; - - if (timestamp == ping_data->timestamp) + + if (serial == ping_data->timestamp) { meta_topic (META_DEBUG_PING, - "Matching ping found for pong %u\n", + "Matching ping found for pong %u\n", ping_data->timestamp); /* Remove the ping data from the list */ @@ -4854,13 +2627,12 @@ process_pong_message (MetaDisplay *display, g_source_remove (ping_data->ping_timeout_id); ping_data->ping_timeout_id = 0; } - + /* Call callback */ - (* ping_data->ping_reply_func) (display, - ping_data->xwindow, - ping_data->timestamp, + (* ping_data->ping_reply_func) (ping_data->window, + ping_data->timestamp, ping_data->user_data); - + ping_data_free (ping_data); break; @@ -4868,38 +2640,8 @@ process_pong_message (MetaDisplay *display, } } -/** - * meta_display_window_has_pending_pings: - * @display: The #MetaDisplay of the window. - * @window: The #MetaWindow whose pings we want to know about. - * - * Finds whether a window has any pings waiting on it. - * - * FIXME: This should probably be a method on windows, rather than displays - * for one of their windows. - * - * Returns: %TRUE if there is at least one ping which has been sent - * to the window without getting a response; %FALSE otherwise. - */ -gboolean -meta_display_window_has_pending_pings (MetaDisplay *display, - MetaWindow *window) -{ - GSList *tmp; - - for (tmp = display->pending_pings; tmp; tmp = tmp->next) - { - MetaPingData *ping_data = tmp->data; - - if (ping_data->xwindow == window->xwindow) - return TRUE; - } - - return FALSE; -} - -MetaGroup* -get_focussed_group (MetaDisplay *display) +static MetaGroup * +get_focused_group (MetaDisplay *display) { if (display->focus_window) return display->focus_window->group; @@ -4909,13 +2651,12 @@ get_focussed_group (MetaDisplay *display) #define IN_TAB_CHAIN(w,t) (((t) == META_TAB_LIST_NORMAL && META_WINDOW_IN_NORMAL_TAB_CHAIN (w)) \ || ((t) == META_TAB_LIST_DOCKS && META_WINDOW_IN_DOCK_TAB_CHAIN (w)) \ - || ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focussed_group(w->display))) \ + || ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focused_group (w->display))) \ || ((t) == META_TAB_LIST_NORMAL_ALL && META_WINDOW_IN_NORMAL_TAB_CHAIN_TYPE (w))) static MetaWindow* find_tab_forward (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace, GList *start, gboolean skip_first) @@ -4933,8 +2674,7 @@ find_tab_forward (MetaDisplay *display, { MetaWindow *window = tmp->data; - if (window->screen == screen && - IN_TAB_CHAIN (window, type)) + if (IN_TAB_CHAIN (window, type)) return window; tmp = tmp->next; @@ -4957,7 +2697,6 @@ find_tab_forward (MetaDisplay *display, static MetaWindow* find_tab_backward (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace, GList *start, gboolean skip_last) @@ -4974,8 +2713,7 @@ find_tab_backward (MetaDisplay *display, { MetaWindow *window = tmp->data; - if (window->screen == screen && - IN_TAB_CHAIN (window, type)) + if (IN_TAB_CHAIN (window, type)) return window; tmp = tmp->prev; @@ -5055,8 +2793,7 @@ meta_display_get_tab_list (MetaDisplay *display, { MetaWindow *window = tmp->data; - if (window->screen == screen && - IN_TAB_CHAIN (window, type)) + if (IN_TAB_CHAIN (window, type)) tab_list = g_list_prepend (tab_list, window); } @@ -5086,7 +2823,6 @@ meta_display_get_tab_list (MetaDisplay *display, * meta_display_get_tab_next: * @display: a #MetaDisplay * @type: type of tab list - * @screen: a #MetaScreen * @workspace: origin workspace * @window: (allow-none): starting window * @backward: If %TRUE, look for the previous window. @@ -5100,7 +2836,6 @@ meta_display_get_tab_list (MetaDisplay *display, MetaWindow* meta_display_get_tab_next (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace, MetaWindow *window, gboolean backward) @@ -5108,10 +2843,7 @@ meta_display_get_tab_next (MetaDisplay *display, gboolean skip; GList *tab_list; MetaWindow *ret; - tab_list = meta_display_get_tab_list(display, - type, - screen, - workspace); + tab_list = meta_display_get_tab_list (display, type, NULL, workspace); if (tab_list == NULL) return NULL; @@ -5121,26 +2853,18 @@ meta_display_get_tab_next (MetaDisplay *display, g_assert (window->display == display); if (backward) - ret = find_tab_backward (display, type, screen, workspace, - g_list_find (tab_list, - window), - TRUE); + ret = find_tab_backward (display, type, workspace, g_list_find (tab_list, window), TRUE); else - ret = find_tab_forward (display, type, screen, workspace, - g_list_find (tab_list, - window), - TRUE); + ret = find_tab_forward (display, type, workspace, g_list_find (tab_list, window), TRUE); } else { skip = display->focus_window != NULL && tab_list->data == display->focus_window; if (backward) - ret = find_tab_backward (display, type, screen, workspace, - tab_list, skip); + ret = find_tab_backward (display, type, workspace, tab_list, skip); else - ret = find_tab_forward (display, type, screen, workspace, - tab_list, skip); + ret = find_tab_forward (display, type, workspace, tab_list, skip); } g_list_free (tab_list); @@ -5151,7 +2875,6 @@ meta_display_get_tab_next (MetaDisplay *display, * meta_display_get_tab_current: * @display: a #MetaDisplay * @type: type of tab list - * @screen: a #MetaScreen * @workspace: origin workspace * * Determine the active window that should be displayed for Alt-TAB. @@ -5162,7 +2885,6 @@ meta_display_get_tab_next (MetaDisplay *display, MetaWindow* meta_display_get_tab_current (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace) { MetaWindow *window; @@ -5170,7 +2892,6 @@ meta_display_get_tab_current (MetaDisplay *display, window = display->focus_window; if (window != NULL && - window->screen == screen && IN_TAB_CHAIN (window, type) && (workspace == NULL || meta_window_located_on_workspace (window, workspace))) @@ -5229,222 +2950,6 @@ meta_resize_gravity_from_grab_op (MetaGrabOp op) return gravity; } -static MetaScreen* -find_screen_for_selection (MetaDisplay *display, - Window owner, - Atom selection) -{ - GSList *tmp; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - if (screen->wm_sn_selection_window == owner && - screen->wm_sn_atom == selection) - return screen; - - tmp = tmp->next; - } - - return NULL; -} - -/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ -static gboolean -convert_property (MetaDisplay *display, - MetaScreen *screen, - Window w, - Atom target, - Atom property) -{ -#define N_TARGETS 4 - Atom conversion_targets[N_TARGETS]; - long icccm_version[] = { 2, 0 }; - - conversion_targets[0] = display->atom_TARGETS; - conversion_targets[1] = display->atom_MULTIPLE; - conversion_targets[2] = display->atom_TIMESTAMP; - conversion_targets[3] = display->atom_VERSION; - - meta_error_trap_push_with_return (display); - if (target == display->atom_TARGETS) - XChangeProperty (display->xdisplay, w, property, - XA_ATOM, 32, PropModeReplace, - (unsigned char *)conversion_targets, N_TARGETS); - else if (target == display->atom_TIMESTAMP) - XChangeProperty (display->xdisplay, w, property, - XA_INTEGER, 32, PropModeReplace, - (unsigned char *)&screen->wm_sn_timestamp, 1); - else if (target == display->atom_VERSION) - XChangeProperty (display->xdisplay, w, property, - XA_INTEGER, 32, PropModeReplace, - (unsigned char *)icccm_version, 2); - else - { - meta_error_trap_pop_with_return (display); - return FALSE; - } - - if (meta_error_trap_pop_with_return (display) != Success) - return FALSE; - - /* Be sure the PropertyNotify has arrived so we - * can send SelectionNotify - */ - /* FIXME the error trap pop synced anyway, right? */ - meta_topic (META_DEBUG_SYNC, "Syncing on %s\n", G_STRFUNC); - XSync (display->xdisplay, False); - - return TRUE; -} - -/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ -static void -process_selection_request (MetaDisplay *display, - XEvent *event) -{ - XSelectionEvent reply; - MetaScreen *screen; - - screen = find_screen_for_selection (display, - event->xselectionrequest.owner, - event->xselectionrequest.selection); - - if (screen == NULL) - { - char *str; - - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xselectionrequest.selection); - meta_error_trap_pop (display); - - meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize\n", - str ? str : "(bad atom)", event->xselectionrequest.owner); - - meta_XFree (str); - - return; - } - - reply.type = SelectionNotify; - reply.display = display->xdisplay; - reply.requestor = event->xselectionrequest.requestor; - reply.selection = event->xselectionrequest.selection; - reply.target = event->xselectionrequest.target; - reply.property = None; - reply.time = event->xselectionrequest.time; - - if (event->xselectionrequest.target == display->atom_MULTIPLE) - { - if (event->xselectionrequest.property != None) - { - Atom type, *adata; - int i, format; - unsigned long num, rest; - unsigned char *data; - - meta_error_trap_push_with_return (display); - if (XGetWindowProperty (display->xdisplay, - event->xselectionrequest.requestor, - event->xselectionrequest.property, 0, 256, False, - display->atom_ATOM_PAIR, - &type, &format, &num, &rest, &data) != Success) - { - meta_error_trap_pop_with_return (display); - return; - } - - if (meta_error_trap_pop_with_return (display) == Success) - { - /* FIXME: to be 100% correct, should deal with rest > 0, - * but since we have 4 possible targets, we will hardly ever - * meet multiple requests with a length > 8 - */ - adata = (Atom*)data; - i = 0; - while (i < (int) num) - { - if (!convert_property (display, screen, - event->xselectionrequest.requestor, - adata[i], adata[i+1])) - adata[i+1] = None; - i += 2; - } - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, - event->xselectionrequest.requestor, - event->xselectionrequest.property, - display->atom_ATOM_PAIR, - 32, PropModeReplace, data, num); - meta_error_trap_pop (display); - meta_XFree (data); - } - } - } - else - { - if (event->xselectionrequest.property == None) - event->xselectionrequest.property = event->xselectionrequest.target; - - if (convert_property (display, screen, - event->xselectionrequest.requestor, - event->xselectionrequest.target, - event->xselectionrequest.property)) - reply.property = event->xselectionrequest.property; - } - - XSendEvent (display->xdisplay, - event->xselectionrequest.requestor, - False, 0L, (XEvent*)&reply); - - meta_verbose ("Handled selection request\n"); -} - -static void -process_selection_clear (MetaDisplay *display, - XEvent *event) -{ - /* We need to unmanage the screen on which we lost the selection */ - MetaScreen *screen; - - screen = find_screen_for_selection (display, - event->xselectionclear.window, - event->xselectionclear.selection); - - - if (screen != NULL) - { - meta_verbose ("Got selection clear for screen %d on display %s\n", - screen->number, display->name); - - meta_display_unmanage_screen (display, - screen, - event->xselectionclear.time); - - /* display and screen may both be invalid memory... */ - - return; - } - - { - char *str; - - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xselectionclear.selection); - meta_error_trap_pop (display); - - meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize\n", - str ? str : "(bad atom)", event->xselectionclear.window); - - meta_XFree (str); - } -} - void meta_display_unmanage_screen (MetaDisplay *display, MetaScreen *screen, @@ -5452,14 +2957,7 @@ meta_display_unmanage_screen (MetaDisplay *display, { meta_verbose ("Unmanaging screen %d on display %s\n", screen->number, display->name); - - g_return_if_fail (g_slist_find (display->screens, screen) != NULL); - - meta_screen_free (screen, timestamp); - display->screens = g_slist_remove (display->screens, screen); - - if (display->screens == NULL) - meta_display_close (display, timestamp); + meta_display_close (display, timestamp); } void @@ -5501,15 +2999,7 @@ meta_display_stack_cmp (const void *a, MetaWindow *aw = (void*) a; MetaWindow *bw = (void*) b; - if (aw->screen == bw->screen) - return meta_stack_windows_cmp (aw->screen->stack, aw, bw); - /* Then assume screens are stacked by number */ - else if (aw->screen->number < bw->screen->number) - return -1; - else if (aw->screen->number > bw->screen->number) - return 1; - else - return 0; /* not reached in theory, if windows on same display */ + return meta_stack_windows_cmp (aw->screen->stack, aw, bw); } /** @@ -5571,7 +3061,6 @@ meta_display_devirtualize_modifiers (MetaDisplay *display, static void update_window_grab_modifiers (MetaDisplay *display) - { MetaVirtualModifier virtual_mods; unsigned int mods; @@ -5645,7 +3134,7 @@ meta_display_increment_focus_sentinel (MetaDisplay *display) data[0] = meta_display_get_current_time (display); XChangeProperty (display->xdisplay, - ((MetaScreen*) display->screens->data)->xroot, + display->screen->xroot, display->atom__MUTTER_SENTINEL, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 1); @@ -5668,9 +3157,9 @@ meta_display_focus_sentinel_clear (MetaDisplay *display) return (display->sentinel_counter == 0); } -static void -sanity_check_timestamps (MetaDisplay *display, - guint32 timestamp) +void +meta_display_sanity_check_timestamps (MetaDisplay *display, + guint32 timestamp) { if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_focus_time)) { @@ -5722,27 +3211,12 @@ meta_display_set_input_focus_window (MetaDisplay *display, { request_xserver_input_focus_change (display, window->screen, + window, focus_frame ? window->frame->xwindow : window->xwindow, timestamp); } void -meta_display_request_take_focus (MetaDisplay *display, - MetaWindow *window, - guint32 timestamp) -{ - if (timestamp_too_old (display, ×tamp)) - return; - - meta_topic (META_DEBUG_FOCUS, "WM_TAKE_FOCUS(%s, %u)\n", - window->desc, timestamp); - - meta_window_send_icccm_message (window, - display->atom_WM_TAKE_FOCUS, - timestamp); -} - -void meta_display_set_input_focus_xwindow (MetaDisplay *display, MetaScreen *screen, Window window, @@ -5750,6 +3224,7 @@ meta_display_set_input_focus_xwindow (MetaDisplay *display, { request_xserver_input_focus_change (display, screen, + NULL, window, timestamp); } @@ -5761,6 +3236,7 @@ meta_display_focus_the_no_focus_window (MetaDisplay *display, { request_xserver_input_focus_change (display, screen, + NULL, screen->no_focus_window, timestamp); } @@ -5783,13 +3259,14 @@ meta_display_overlay_key_activate (MetaDisplay *display) } void -meta_display_accelerator_activate (MetaDisplay *display, - guint action, - guint deviceid, - guint timestamp) +meta_display_accelerator_activate (MetaDisplay *display, + guint action, + ClutterKeyEvent *event) { g_signal_emit (display, display_signals[ACCELERATOR_ACTIVATED], - 0, action, deviceid, timestamp); + 0, action, + clutter_input_device_get_device_id (event->device), + event->time); } gboolean @@ -5836,7 +3313,7 @@ meta_display_get_xinput_opcode (MetaDisplay *display) gboolean meta_display_supports_extended_barriers (MetaDisplay *display) { - return META_DISPLAY_HAS_XINPUT_23 (display); + return META_DISPLAY_HAS_XINPUT_23 (display) && !meta_is_wayland_compositor (); } /** @@ -5861,18 +3338,6 @@ meta_display_get_compositor (MetaDisplay *display) return display->compositor; } -/** - * meta_display_get_screens: - * @display: a #MetaDisplay - * - * Returns: (transfer none) (element-type Meta.Screen): Screens for this display - */ -GSList * -meta_display_get_screens (MetaDisplay *display) -{ - return display->screens; -} - gboolean meta_display_has_shape (MetaDisplay *display) { @@ -5910,22 +3375,6 @@ meta_display_get_shape_event_base (MetaDisplay *display) #endif /** - * meta_display_get_leader_window: - * @display: a #MetaDisplay - * - * Returns the window manager's leader window (as defined by the - * _NET_SUPPORTING_WM_CHECK mechanism of EWMH). For use by plugins that wish - * to attach additional custom properties to this window. - * - * Return value: (transfer none): xid of the leader window. - **/ -Window -meta_display_get_leader_window (MetaDisplay *display) -{ - return display->leader_window; -} - -/** * meta_display_clear_mouse_mode: * @display: a #MetaDisplay * diff --git a/src/core/edge-resistance.c b/src/core/edge-resistance.c index 6a2648a..8eb48a7 100644 --- a/src/core/edge-resistance.c +++ b/src/core/edge-resistance.c @@ -30,7 +30,6 @@ */ #define WINDOW_EDGES_RELEVANT(window, display) \ meta_window_should_be_showing (window) && \ - window->screen == display->grab_screen && \ window != display->grab_window && \ window->type != META_WINDOW_DESKTOP && \ window->type != META_WINDOW_MENU && \ @@ -963,9 +962,9 @@ compute_resistance_and_snapping_edges (MetaDisplay *display) /* * 1st: Get the list of relevant windows, from bottom to top */ - stacked_windows = - meta_stack_list_windows (display->grab_screen->stack, - display->grab_screen->active_workspace); + stacked_windows = + meta_stack_list_windows (display->screen->stack, + display->screen->active_workspace); /* * 2nd: we need to separate that stacked list into a list of windows that @@ -1026,7 +1025,7 @@ compute_resistance_and_snapping_edges (MetaDisplay *display) * by other windows or DOCKS, but that's handled below). */ meta_rectangle_intersect (&cur_rect, - &display->grab_screen->rect, + &display->screen->rect, &reduced); new_edges = NULL; @@ -1123,8 +1122,8 @@ compute_resistance_and_snapping_edges (MetaDisplay *display) */ cache_edges (display, edges, - display->grab_screen->active_workspace->monitor_edges, - display->grab_screen->active_workspace->screen_edges); + display->screen->active_workspace->monitor_edges, + display->screen->active_workspace->screen_edges); g_list_free (edges); /* diff --git a/src/core/errors.c b/src/core/errors.c index 56a7bd4..f199c69 100644 --- a/src/core/errors.c +++ b/src/core/errors.c @@ -55,12 +55,6 @@ meta_error_trap_pop (MetaDisplay *display) gdk_error_trap_pop_ignored (); } -void -meta_error_trap_push_with_return (MetaDisplay *display) -{ - gdk_error_trap_push (); -} - int meta_error_trap_pop_with_return (MetaDisplay *display) { diff --git a/src/core/events.c b/src/core/events.c new file mode 100644 index 0000000..3cc5488 --- /dev/null +++ b/src/core/events.c @@ -0,0 +1,2224 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. + * Copyright (C) 2003, 2004 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" +#include "events.h" + +#include <X11/Xatom.h> +#include <X11/extensions/Xdamage.h> +#ifdef HAVE_SHAPE +#include <X11/extensions/shape.h> +#endif + +#include <meta/errors.h> +#include "display-private.h" +#include "window-private.h" +#include "bell.h" +#include "workspace-private.h" +#include "backends/x11/meta-idle-monitor-xsync.h" +#include "backends/native/meta-idle-monitor-native.h" + +#include "x11/window-x11.h" +#include "x11/xprops.h" +#include "wayland/meta-xwayland.h" +#include "wayland/meta-wayland-private.h" +#include "meta-surface-actor-wayland.h" + +static MetaWindow * +get_window_for_event (MetaDisplay *display, + const ClutterEvent *event) +{ + ClutterActor *source; + + if (display->grab_op != META_GRAB_OP_NONE) + return display->grab_window; + + /* Always use the key focused window for key events. */ + switch (event->type) + { + case CLUTTER_KEY_PRESS: + case CLUTTER_KEY_RELEASE: + return display->focus_window; + default: + break; + } + + source = clutter_event_get_source (event); + if (META_IS_SURFACE_ACTOR (source)) + return meta_surface_actor_get_window (META_SURFACE_ACTOR (source)); + + return NULL; +} + +static XIEvent * +get_input_event (MetaDisplay *display, + XEvent *event) +{ + if (event->type == GenericEvent && + event->xcookie.extension == display->xinput_opcode) + { + XIEvent *input_event; + + /* NB: GDK event filters already have generic events + * allocated, so no need to do XGetEventData() on our own + */ + input_event = (XIEvent *) event->xcookie.data; + + switch (input_event->evtype) + { + case XI_Motion: + case XI_ButtonPress: + case XI_ButtonRelease: + if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) + return input_event; + break; + case XI_KeyPress: + case XI_KeyRelease: + if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID) + return input_event; + break; + case XI_FocusIn: + case XI_FocusOut: + if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID) + return input_event; + break; + case XI_Enter: + case XI_Leave: + if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) + return input_event; + break; +#ifdef HAVE_XI23 + case XI_BarrierHit: + case XI_BarrierLeave: + if (((XIBarrierEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) + return input_event; + break; +#endif /* HAVE_XI23 */ + default: + break; + } + } + + return NULL; +} + +static Window +xievent_get_modified_window (MetaDisplay *display, + XIEvent *input_event) +{ + switch (input_event->evtype) + { + case XI_Motion: + case XI_ButtonPress: + case XI_ButtonRelease: + case XI_KeyPress: + case XI_KeyRelease: + return ((XIDeviceEvent *) input_event)->event; + case XI_FocusIn: + case XI_FocusOut: + case XI_Enter: + case XI_Leave: + return ((XIEnterEvent *) input_event)->event; +#ifdef HAVE_XI23 + case XI_BarrierHit: + case XI_BarrierLeave: + return ((XIBarrierEvent *) input_event)->event; +#endif /* HAVE_XI23 */ + } + + return None; +} + +/* Return the window this has to do with, if any, rather + * than the frame or root window that was selecting + * for substructure + */ +static Window +event_get_modified_window (MetaDisplay *display, + XEvent *event) +{ + XIEvent *input_event = get_input_event (display, event); + + if (input_event) + return xievent_get_modified_window (display, input_event); + + switch (event->type) + { + case KeymapNotify: + case Expose: + case GraphicsExpose: + case NoExpose: + case VisibilityNotify: + case ResizeRequest: + case PropertyNotify: + case SelectionClear: + case SelectionRequest: + case SelectionNotify: + case ColormapNotify: + case ClientMessage: + return event->xany.window; + + case CreateNotify: + return event->xcreatewindow.window; + + case DestroyNotify: + return event->xdestroywindow.window; + + case UnmapNotify: + return event->xunmap.window; + + case MapNotify: + return event->xmap.window; + + case MapRequest: + return event->xmaprequest.window; + + case ReparentNotify: + return event->xreparent.window; + + case ConfigureNotify: + return event->xconfigure.window; + + case ConfigureRequest: + return event->xconfigurerequest.window; + + case GravityNotify: + return event->xgravity.window; + + case CirculateNotify: + return event->xcirculate.window; + + case CirculateRequest: + return event->xcirculaterequest.window; + + case MappingNotify: + return None; + + default: +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (display) && + event->type == (display->shape_event_base + ShapeNotify)) + { + XShapeEvent *sev = (XShapeEvent*) event; + return sev->window; + } +#endif + + return None; + } +} + +static guint32 +event_get_time (MetaDisplay *display, + XEvent *event) +{ + XIEvent *input_event = get_input_event (display, event); + + if (input_event) + return input_event->time; + + switch (event->type) + { + case PropertyNotify: + return event->xproperty.time; + + case SelectionClear: + case SelectionRequest: + case SelectionNotify: + return event->xselection.time; + + case KeymapNotify: + case Expose: + case GraphicsExpose: + case NoExpose: + case MapNotify: + case UnmapNotify: + case VisibilityNotify: + case ResizeRequest: + case ColormapNotify: + case ClientMessage: + case CreateNotify: + case DestroyNotify: + case MapRequest: + case ReparentNotify: + case ConfigureNotify: + case ConfigureRequest: + case GravityNotify: + case CirculateNotify: + case CirculateRequest: + case MappingNotify: + default: + return CurrentTime; + } +} + +G_GNUC_UNUSED const char* +meta_event_detail_to_string (int d) +{ + const char *detail = "???"; + switch (d) + { + /* We are an ancestor in the A<->B focus change relationship */ + case XINotifyAncestor: + detail = "NotifyAncestor"; + break; + case XINotifyDetailNone: + detail = "NotifyDetailNone"; + break; + /* We are a descendant in the A<->B focus change relationship */ + case XINotifyInferior: + detail = "NotifyInferior"; + break; + case XINotifyNonlinear: + detail = "NotifyNonlinear"; + break; + case XINotifyNonlinearVirtual: + detail = "NotifyNonlinearVirtual"; + break; + case XINotifyPointer: + detail = "NotifyPointer"; + break; + case XINotifyPointerRoot: + detail = "NotifyPointerRoot"; + break; + case XINotifyVirtual: + detail = "NotifyVirtual"; + break; + } + + return detail; +} + +G_GNUC_UNUSED const char* +meta_event_mode_to_string (int m) +{ + const char *mode = "???"; + switch (m) + { + case XINotifyNormal: + mode = "NotifyNormal"; + break; + case XINotifyGrab: + mode = "NotifyGrab"; + break; + case XINotifyUngrab: + mode = "NotifyUngrab"; + break; + case XINotifyWhileGrabbed: + mode = "NotifyWhileGrabbed"; + break; + } + + return mode; +} + +G_GNUC_UNUSED static const char* +stack_mode_to_string (int mode) +{ + switch (mode) + { + case Above: + return "Above"; + case Below: + return "Below"; + case TopIf: + return "TopIf"; + case BottomIf: + return "BottomIf"; + case Opposite: + return "Opposite"; + } + + return "Unknown"; +} + +#ifdef HAVE_XSYNC +G_GNUC_UNUSED static gint64 +sync_value_to_64 (const XSyncValue *value) +{ + gint64 v; + + v = XSyncValueLow32 (*value); + v |= (((gint64)XSyncValueHigh32 (*value)) << 32); + + return v; +} + +G_GNUC_UNUSED static const char* +alarm_state_to_string (XSyncAlarmState state) +{ + switch (state) + { + case XSyncAlarmActive: + return "Active"; + case XSyncAlarmInactive: + return "Inactive"; + case XSyncAlarmDestroyed: + return "Destroyed"; + default: + return "(unknown)"; + } +} +#endif /* HAVE_XSYNC */ + +G_GNUC_UNUSED static void +meta_spew_xi2_event (MetaDisplay *display, + XIEvent *input_event, + const char **name_p, + char **extra_p) +{ + const char *name = NULL; + char *extra = NULL; + + XIEnterEvent *enter_event = (XIEnterEvent *) input_event; + + switch (input_event->evtype) + { + case XI_FocusIn: + name = "XI_FocusIn"; + break; + case XI_FocusOut: + name = "XI_FocusOut"; + break; + case XI_Enter: + name = "XI_Enter"; + break; + case XI_Leave: + name = "XI_Leave"; + break; +#ifdef HAVE_XI23 + case XI_BarrierHit: + name = "XI_BarrierHit"; + break; + case XI_BarrierLeave: + name = "XI_BarrierLeave"; + break; +#endif /* HAVE_XI23 */ + } + + switch (input_event->evtype) + { + case XI_FocusIn: + case XI_FocusOut: + extra = g_strdup_printf ("detail: %s mode: %s\n", + meta_event_detail_to_string (enter_event->detail), + meta_event_mode_to_string (enter_event->mode)); + break; + case XI_Enter: + case XI_Leave: + extra = g_strdup_printf ("win: 0x%lx root: 0x%lx mode: %s detail: %s focus: %d x: %g y: %g", + enter_event->event, + enter_event->root, + meta_event_mode_to_string (enter_event->mode), + meta_event_detail_to_string (enter_event->detail), + enter_event->focus, + enter_event->root_x, + enter_event->root_y); + break; + } + + *name_p = name; + *extra_p = extra; +} + +G_GNUC_UNUSED static void +meta_spew_core_event (MetaDisplay *display, + XEvent *event, + const char **name_p, + char **extra_p) +{ + const char *name = NULL; + char *extra = NULL; + + switch (event->type) + { + case KeymapNotify: + name = "KeymapNotify"; + break; + case Expose: + name = "Expose"; + break; + case GraphicsExpose: + name = "GraphicsExpose"; + break; + case NoExpose: + name = "NoExpose"; + break; + case VisibilityNotify: + name = "VisibilityNotify"; + break; + case CreateNotify: + name = "CreateNotify"; + extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx", + event->xcreatewindow.parent, + event->xcreatewindow.window); + break; + case DestroyNotify: + name = "DestroyNotify"; + extra = g_strdup_printf ("event: 0x%lx window: 0x%lx", + event->xdestroywindow.event, + event->xdestroywindow.window); + break; + case UnmapNotify: + name = "UnmapNotify"; + extra = g_strdup_printf ("event: 0x%lx window: 0x%lx from_configure: %d", + event->xunmap.event, + event->xunmap.window, + event->xunmap.from_configure); + break; + case MapNotify: + name = "MapNotify"; + extra = g_strdup_printf ("event: 0x%lx window: 0x%lx override_redirect: %d", + event->xmap.event, + event->xmap.window, + event->xmap.override_redirect); + break; + case MapRequest: + name = "MapRequest"; + extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n", + event->xmaprequest.window, + event->xmaprequest.parent); + break; + case ReparentNotify: + name = "ReparentNotify"; + extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx event: 0x%lx\n", + event->xreparent.window, + event->xreparent.parent, + event->xreparent.event); + break; + case ConfigureNotify: + name = "ConfigureNotify"; + extra = g_strdup_printf ("x: %d y: %d w: %d h: %d above: 0x%lx override_redirect: %d", + event->xconfigure.x, + event->xconfigure.y, + event->xconfigure.width, + event->xconfigure.height, + event->xconfigure.above, + event->xconfigure.override_redirect); + break; + case ConfigureRequest: + name = "ConfigureRequest"; + extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx x: %d %sy: %d %sw: %d %sh: %d %sborder: %d %sabove: %lx %sstackmode: %s %s", + event->xconfigurerequest.parent, + event->xconfigurerequest.window, + event->xconfigurerequest.x, + event->xconfigurerequest.value_mask & + CWX ? "" : "(unset) ", + event->xconfigurerequest.y, + event->xconfigurerequest.value_mask & + CWY ? "" : "(unset) ", + event->xconfigurerequest.width, + event->xconfigurerequest.value_mask & + CWWidth ? "" : "(unset) ", + event->xconfigurerequest.height, + event->xconfigurerequest.value_mask & + CWHeight ? "" : "(unset) ", + event->xconfigurerequest.border_width, + event->xconfigurerequest.value_mask & + CWBorderWidth ? "" : "(unset)", + event->xconfigurerequest.above, + event->xconfigurerequest.value_mask & + CWSibling ? "" : "(unset)", + stack_mode_to_string (event->xconfigurerequest.detail), + event->xconfigurerequest.value_mask & + CWStackMode ? "" : "(unset)"); + break; + case GravityNotify: + name = "GravityNotify"; + break; + case ResizeRequest: + name = "ResizeRequest"; + extra = g_strdup_printf ("width = %d height = %d", + event->xresizerequest.width, + event->xresizerequest.height); + break; + case CirculateNotify: + name = "CirculateNotify"; + break; + case CirculateRequest: + name = "CirculateRequest"; + break; + case PropertyNotify: + { + char *str; + const char *state; + + name = "PropertyNotify"; + + meta_error_trap_push (display); + str = XGetAtomName (display->xdisplay, + event->xproperty.atom); + meta_error_trap_pop (display); + + if (event->xproperty.state == PropertyNewValue) + state = "PropertyNewValue"; + else if (event->xproperty.state == PropertyDelete) + state = "PropertyDelete"; + else + state = "???"; + + extra = g_strdup_printf ("atom: %s state: %s", + str ? str : "(unknown atom)", + state); + meta_XFree (str); + } + break; + case SelectionClear: + name = "SelectionClear"; + break; + case SelectionRequest: + name = "SelectionRequest"; + break; + case SelectionNotify: + name = "SelectionNotify"; + break; + case ColormapNotify: + name = "ColormapNotify"; + break; + case ClientMessage: + { + char *str; + name = "ClientMessage"; + meta_error_trap_push (display); + str = XGetAtomName (display->xdisplay, + event->xclient.message_type); + meta_error_trap_pop (display); + extra = g_strdup_printf ("type: %s format: %d\n", + str ? str : "(unknown atom)", + event->xclient.format); + meta_XFree (str); + } + break; + case MappingNotify: + name = "MappingNotify"; + break; + default: +#ifdef HAVE_XSYNC + if (META_DISPLAY_HAS_XSYNC (display) && + event->type == (display->xsync_event_base + XSyncAlarmNotify)) + { + XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event; + + name = "XSyncAlarmNotify"; + extra = + g_strdup_printf ("alarm: 0x%lx" + " counter_value: %" G_GINT64_FORMAT + " alarm_value: %" G_GINT64_FORMAT + " time: %u alarm state: %s", + aevent->alarm, + (gint64) sync_value_to_64 (&aevent->counter_value), + (gint64) sync_value_to_64 (&aevent->alarm_value), + (unsigned int)aevent->time, + alarm_state_to_string (aevent->state)); + } + else +#endif /* HAVE_XSYNC */ +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (display) && + event->type == (display->shape_event_base + ShapeNotify)) + { + XShapeEvent *sev = (XShapeEvent*) event; + + name = "ShapeNotify"; + + extra = + g_strdup_printf ("kind: %s " + "x: %d y: %d w: %u h: %u " + "shaped: %d", + sev->kind == ShapeBounding ? + "ShapeBounding" : + (sev->kind == ShapeClip ? + "ShapeClip" : "(unknown)"), + sev->x, sev->y, sev->width, sev->height, + sev->shaped); + } + else +#endif /* HAVE_SHAPE */ + { + name = "(Unknown event)"; + extra = g_strdup_printf ("type: %d", event->xany.type); + } + break; + } + + *name_p = name; + *extra_p = extra; +} + +G_GNUC_UNUSED static void +meta_spew_event (MetaDisplay *display, + XEvent *event) +{ + MetaScreen *screen = display->screen; + const char *name = NULL; + char *extra = NULL; + char *winname; + XIEvent *input_event; + + /* filter overnumerous events */ + if (event->type == Expose || event->type == MotionNotify || + event->type == NoExpose) + return; + + if (event->type == (display->damage_event_base + XDamageNotify)) + return; + + if (event->type == (display->xsync_event_base + XSyncAlarmNotify)) + return; + + if (event->type == PropertyNotify && event->xproperty.atom == display->atom__NET_WM_USER_TIME) + return; + + input_event = get_input_event (display, event); + + if (input_event) + meta_spew_xi2_event (display, input_event, &name, &extra); + else + meta_spew_core_event (display, event, &name, &extra); + + if (event->xany.window == screen->xroot) + winname = g_strdup_printf ("root %d", screen->number); + else + winname = g_strdup_printf ("0x%lx", event->xany.window); + + g_print ("%s on %s%s %s %sserial %lu\n", name, winname, + extra ? ":" : "", extra ? extra : "", + event->xany.send_event ? "SEND " : "", + event->xany.serial); + + g_free (winname); + + if (extra) + g_free (extra); +} + +static void +handle_window_focus_event (MetaDisplay *display, + MetaWindow *window, + XIEnterEvent *event, + unsigned long serial) +{ + MetaWindow *focus_window; +#ifdef WITH_VERBOSE_MODE + const char *window_type; + + /* Note the event can be on either the window or the frame, + * we focus the frame for shaded windows + */ + if (window) + { + if (event->event == window->xwindow) + window_type = "client window"; + else if (window->frame && event->event == window->frame->xwindow) + window_type = "frame window"; + else + window_type = "unknown client window"; + } + else if (meta_display_xwindow_is_a_no_focus_window (display, event->event)) + window_type = "no_focus_window"; + else if (event->event == display->screen->xroot) + window_type = "root window"; + else + window_type = "unknown window"; + + meta_topic (META_DEBUG_FOCUS, + "Focus %s event received on %s 0x%lx (%s) " + "mode %s detail %s serial %lu\n", + event->evtype == XI_FocusIn ? "in" : + event->evtype == XI_FocusOut ? "out" : + "???", + window ? window->desc : "", + event->event, window_type, + meta_event_mode_to_string (event->mode), + meta_event_detail_to_string (event->mode), + event->serial); +#endif + + /* FIXME our pointer tracking is broken; see how + * gtk+/gdk/x11/gdkevents-x11.c or XFree86/xc/programs/xterm/misc.c + * for how to handle it the correct way. In brief you need to track + * pointer focus and regular focus, and handle EnterNotify in + * PointerRoot mode with no window manager. However as noted above, + * accurate focus tracking will break things because we want to keep + * windows "focused" when using keybindings on them, and also we + * sometimes "focus" a window by focusing its frame or + * no_focus_window; so this all needs rethinking massively. + * + * My suggestion is to change it so that we clearly separate + * actual keyboard focus tracking using the xterm algorithm, + * and mutter's "pretend" focus window, and go through all + * the code and decide which one should be used in each place; + * a hard bit is deciding on a policy for that. + * + * http://bugzilla.gnome.org/show_bug.cgi?id=90382 + */ + + /* We ignore grabs, though this is questionable. It may be better to + * increase the intelligence of the focus window tracking. + * + * The problem is that keybindings for windows are done with + * XGrabKey, which means focus_window disappears and the front of + * the MRU list gets confused from what the user expects once a + * keybinding is used. + */ + + if (event->mode == XINotifyGrab || + event->mode == XINotifyUngrab || + /* From WindowMaker, ignore all funky pointer root events */ + event->detail > XINotifyNonlinearVirtual) + { + meta_topic (META_DEBUG_FOCUS, + "Ignoring focus event generated by a grab or other weirdness\n"); + return; + } + + if (event->evtype == XI_FocusIn) + { + display->server_focus_window = event->event; + display->server_focus_serial = serial; + focus_window = window; + } + else if (event->evtype == XI_FocusOut) + { + if (event->detail == XINotifyInferior) + { + /* This event means the client moved focus to a subwindow */ + meta_topic (META_DEBUG_FOCUS, + "Ignoring focus out with NotifyInferior\n"); + return; + } + + display->server_focus_window = None; + display->server_focus_serial = serial; + focus_window = NULL; + } + else + g_return_if_reached (); + + /* If display->focused_by_us, then the focus_serial will be used only + * for a focus change we made and have already accounted for. + * (See request_xserver_input_focus_change().) Otherwise, we can get + * multiple focus events with the same serial. + */ + if (display->server_focus_serial > display->focus_serial || + (!display->focused_by_us && + display->server_focus_serial == display->focus_serial)) + { + meta_display_update_focus_window (display, + focus_window, + focus_window ? focus_window->xwindow : None, + display->server_focus_serial, + FALSE); + } +} + +static gboolean +crossing_serial_is_ignored (MetaDisplay *display, + unsigned long serial) +{ + int i; + + i = 0; + while (i < N_IGNORED_CROSSING_SERIALS) + { + if (display->ignored_crossing_serials[i] == serial) + return TRUE; + ++i; + } + return FALSE; +} + +static gboolean +handle_input_xevent (MetaDisplay *display, + XIEvent *input_event, + gulong serial) +{ + XIEnterEvent *enter_event = (XIEnterEvent *) input_event; + Window modified; + MetaWindow *window; + MetaScreen *screen = display->screen; + + if (input_event == NULL) + return FALSE; + + switch (input_event->evtype) + { + case XI_Enter: + case XI_Leave: + case XI_FocusIn: + case XI_FocusOut: + break; + default: + return FALSE; + } + + modified = xievent_get_modified_window (display, input_event); + window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL; + + /* If this is an event for a GTK+ widget, let GTK+ handle it. */ + if (meta_ui_window_is_widget (display->screen->ui, modified)) + return FALSE; + + switch (input_event->evtype) + { + case XI_Enter: + if (display->grab_op == META_GRAB_OP_COMPOSITOR) + break; + + /* Check if we've entered a window; do this even if window->has_focus to + * avoid races. + */ + if (window && !crossing_serial_is_ignored (display, serial) && + enter_event->mode != XINotifyGrab && + enter_event->mode != XINotifyUngrab && + enter_event->detail != XINotifyInferior && + meta_display_focus_sentinel_clear (display)) + { + meta_window_handle_enter (window, + enter_event->time, + enter_event->root_x, + enter_event->root_y); + + if (window->type == META_WINDOW_DOCK) + meta_window_raise (window); + } + break; + case XI_Leave: + if (display->grab_op == META_GRAB_OP_COMPOSITOR) + break; + + if (window != NULL) + { + if (window->type == META_WINDOW_DOCK && + enter_event->mode != XINotifyGrab && + enter_event->mode != XINotifyUngrab && + !window->has_focus) + meta_window_lower (window); + } + break; + case XI_FocusIn: + case XI_FocusOut: + handle_window_focus_event (display, window, enter_event, serial); + if (!window) + { + /* Check if the window is a root window. */ + if (enter_event->root != enter_event->event) + break; + + if (enter_event->evtype == XI_FocusIn && + enter_event->mode == XINotifyDetailNone) + { + meta_topic (META_DEBUG_FOCUS, + "Focus got set to None, probably due to " + "brain-damage in the X protocol (see bug " + "125492). Setting the default focus window.\n"); + meta_workspace_focus_default_window (screen->active_workspace, + NULL, + meta_display_get_current_time_roundtrip (display)); + } + else if (enter_event->evtype == XI_FocusIn && + enter_event->mode == XINotifyNormal && + enter_event->detail == XINotifyInferior) + { + meta_topic (META_DEBUG_FOCUS, + "Focus got set to root window, probably due to " + "gnome-session logout dialog usage (see bug " + "153220). Setting the default focus window.\n"); + meta_workspace_focus_default_window (screen->active_workspace, + NULL, + meta_display_get_current_time_roundtrip (display)); + } + + } + break; + } + + /* Don't pass these events through to Clutter / GTK+ */ + return TRUE; +} + +static void +reload_xkb_rules (MetaScreen *screen) +{ + MetaWaylandCompositor *compositor; + char **names; + int n_names; + gboolean ok; + const char *rules, *model, *layout, *variant, *options; + + compositor = meta_wayland_compositor_get_default (); + + ok = meta_prop_get_latin1_list (screen->display, screen->xroot, + screen->display->atom__XKB_RULES_NAMES, + &names, &n_names); + if (!ok) + return; + + if (n_names != 5) + goto out; + + rules = names[0]; + model = names[1]; + layout = names[2]; + variant = names[3]; + options = names[4]; + + meta_wayland_keyboard_set_keymap_names (&compositor->seat->keyboard, + rules, model, layout, variant, options, + META_WAYLAND_KEYBOARD_SKIP_XCLIENTS); + + out: + g_strfreev (names); +} + +static void +process_request_frame_extents (MetaDisplay *display, + XEvent *event) +{ + /* The X window whose frame extents will be set. */ + Window xwindow = event->xclient.window; + unsigned long data[4] = { 0, 0, 0, 0 }; + + MotifWmHints *hints = NULL; + gboolean hints_set = FALSE; + + meta_verbose ("Setting frame extents for 0x%lx\n", xwindow); + + /* See if the window is decorated. */ + hints_set = meta_prop_get_motif_hints (display, + xwindow, + display->atom__MOTIF_WM_HINTS, + &hints); + if ((hints_set && hints->decorations) || !hints_set) + { + MetaFrameBorders borders; + + /* Return estimated frame extents for a normal window. */ + meta_ui_theme_get_frame_borders (display->screen->ui, + META_FRAME_TYPE_NORMAL, + 0, + &borders); + data[0] = borders.visible.left; + data[1] = borders.visible.right; + data[2] = borders.visible.top; + data[3] = borders.visible.bottom; + } + + meta_topic (META_DEBUG_GEOMETRY, + "Setting _NET_FRAME_EXTENTS on unmanaged window 0x%lx " + "to top = %lu, left = %lu, bottom = %lu, right = %lu\n", + xwindow, data[0], data[1], data[2], data[3]); + + meta_error_trap_push (display); + XChangeProperty (display->xdisplay, xwindow, + display->atom__NET_FRAME_EXTENTS, + XA_CARDINAL, + 32, PropModeReplace, (guchar*) data, 4); + meta_error_trap_pop (display); + + meta_XFree (hints); +} + +/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ +static gboolean +convert_property (MetaDisplay *display, + MetaScreen *screen, + Window w, + Atom target, + Atom property) +{ +#define N_TARGETS 4 + Atom conversion_targets[N_TARGETS]; + long icccm_version[] = { 2, 0 }; + + conversion_targets[0] = display->atom_TARGETS; + conversion_targets[1] = display->atom_MULTIPLE; + conversion_targets[2] = display->atom_TIMESTAMP; + conversion_targets[3] = display->atom_VERSION; + + meta_error_trap_push (display); + if (target == display->atom_TARGETS) + XChangeProperty (display->xdisplay, w, property, + XA_ATOM, 32, PropModeReplace, + (unsigned char *)conversion_targets, N_TARGETS); + else if (target == display->atom_TIMESTAMP) + XChangeProperty (display->xdisplay, w, property, + XA_INTEGER, 32, PropModeReplace, + (unsigned char *)&screen->wm_sn_timestamp, 1); + else if (target == display->atom_VERSION) + XChangeProperty (display->xdisplay, w, property, + XA_INTEGER, 32, PropModeReplace, + (unsigned char *)icccm_version, 2); + else + { + meta_error_trap_pop_with_return (display); + return FALSE; + } + + if (meta_error_trap_pop_with_return (display) != Success) + return FALSE; + + /* Be sure the PropertyNotify has arrived so we + * can send SelectionNotify + */ + /* FIXME the error trap pop synced anyway, right? */ + meta_topic (META_DEBUG_SYNC, "Syncing on %s\n", G_STRFUNC); + XSync (display->xdisplay, False); + + return TRUE; +} + +/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ +static void +process_selection_request (MetaDisplay *display, + XEvent *event) +{ + MetaScreen *screen = display->screen; + XSelectionEvent reply; + + if (screen->wm_sn_selection_window != event->xselectionrequest.owner || + screen->wm_sn_atom != event->xselectionrequest.selection) + { + char *str; + + meta_error_trap_push (display); + str = XGetAtomName (display->xdisplay, + event->xselectionrequest.selection); + meta_error_trap_pop (display); + + meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize\n", + str ? str : "(bad atom)", event->xselectionrequest.owner); + + meta_XFree (str); + + return; + } + + reply.type = SelectionNotify; + reply.display = display->xdisplay; + reply.requestor = event->xselectionrequest.requestor; + reply.selection = event->xselectionrequest.selection; + reply.target = event->xselectionrequest.target; + reply.property = None; + reply.time = event->xselectionrequest.time; + + if (event->xselectionrequest.target == display->atom_MULTIPLE) + { + if (event->xselectionrequest.property != None) + { + Atom type, *adata; + int i, format; + unsigned long num, rest; + unsigned char *data; + + meta_error_trap_push (display); + if (XGetWindowProperty (display->xdisplay, + event->xselectionrequest.requestor, + event->xselectionrequest.property, 0, 256, False, + display->atom_ATOM_PAIR, + &type, &format, &num, &rest, &data) != Success) + { + meta_error_trap_pop_with_return (display); + return; + } + + if (meta_error_trap_pop_with_return (display) == Success) + { + /* FIXME: to be 100% correct, should deal with rest > 0, + * but since we have 4 possible targets, we will hardly ever + * meet multiple requests with a length > 8 + */ + adata = (Atom*)data; + i = 0; + while (i < (int) num) + { + if (!convert_property (display, screen, + event->xselectionrequest.requestor, + adata[i], adata[i+1])) + adata[i+1] = None; + i += 2; + } + + meta_error_trap_push (display); + XChangeProperty (display->xdisplay, + event->xselectionrequest.requestor, + event->xselectionrequest.property, + display->atom_ATOM_PAIR, + 32, PropModeReplace, data, num); + meta_error_trap_pop (display); + meta_XFree (data); + } + } + } + else + { + if (event->xselectionrequest.property == None) + event->xselectionrequest.property = event->xselectionrequest.target; + + if (convert_property (display, screen, + event->xselectionrequest.requestor, + event->xselectionrequest.target, + event->xselectionrequest.property)) + reply.property = event->xselectionrequest.property; + } + + XSendEvent (display->xdisplay, + event->xselectionrequest.requestor, + False, 0L, (XEvent*)&reply); + + meta_verbose ("Handled selection request\n"); +} + +static void +process_selection_clear (MetaDisplay *display, + XEvent *event) +{ + MetaScreen *screen = display->screen; + + if (screen->wm_sn_selection_window != event->xselectionclear.window || + screen->wm_sn_atom != event->xselectionclear.selection) + { + char *str; + + meta_error_trap_push (display); + str = XGetAtomName (display->xdisplay, + event->xselectionclear.selection); + meta_error_trap_pop (display); + + meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize\n", + str ? str : "(bad atom)", event->xselectionclear.window); + + meta_XFree (str); + + return; + } + + meta_verbose ("Got selection clear for screen %d on display %s\n", + screen->number, display->name); + + meta_display_unmanage_screen (display, display->screen, + event->xselectionclear.time); +} + +static gboolean +handle_other_xevent (MetaDisplay *display, + XEvent *event) +{ + Window modified; + MetaWindow *window; + MetaWindow *property_for_window; + gboolean frame_was_receiver; + gboolean bypass_gtk = FALSE; + + modified = event_get_modified_window (display, event); + window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL; + frame_was_receiver = (window && window->frame && modified == window->frame->xwindow); + + /* We only want to respond to _NET_WM_USER_TIME property notify + * events on _NET_WM_USER_TIME_WINDOW windows; in particular, + * responding to UnmapNotify events is kind of bad. + */ + property_for_window = NULL; + if (window && modified == window->user_time_window) + { + property_for_window = window; + window = NULL; + } + +#ifdef HAVE_XSYNC + if (META_DISPLAY_HAS_XSYNC (display) && + event->type == (display->xsync_event_base + XSyncAlarmNotify)) + { + MetaWindow *alarm_window = meta_display_lookup_sync_alarm (display, + ((XSyncAlarmNotifyEvent*)event)->alarm); + + if (alarm_window != NULL) + { + XSyncValue value = ((XSyncAlarmNotifyEvent*)event)->counter_value; + gint64 new_counter_value; + new_counter_value = XSyncValueLow32 (value) + ((gint64)XSyncValueHigh32 (value) << 32); + meta_window_update_sync_request_counter (alarm_window, new_counter_value); + bypass_gtk = TRUE; /* GTK doesn't want to see this really */ + } + else + meta_idle_monitor_xsync_handle_xevent_all (event); + + goto out; + } +#endif /* HAVE_XSYNC */ + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (display) && + event->type == (display->shape_event_base + ShapeNotify)) + { + bypass_gtk = TRUE; /* GTK doesn't want to see this really */ + + if (window && !frame_was_receiver) + { + XShapeEvent *sev = (XShapeEvent*) event; + + if (sev->kind == ShapeBounding) + meta_window_x11_update_shape_region (window); + else if (sev->kind == ShapeInput) + meta_window_x11_update_input_region (window); + } + else + { + meta_topic (META_DEBUG_SHAPES, + "ShapeNotify not on a client window (window %s frame_was_receiver = %d)\n", + window ? window->desc : "(none)", + frame_was_receiver); + } + + goto out; + } +#endif /* HAVE_SHAPE */ + + switch (event->type) + { + case KeymapNotify: + break; + case Expose: + break; + case GraphicsExpose: + break; + case NoExpose: + break; + case VisibilityNotify: + break; + case CreateNotify: + { + if (event->xcreatewindow.parent == display->screen->xroot) + meta_stack_tracker_create_event (display->screen->stack_tracker, + &event->xcreatewindow); + } + break; + + case DestroyNotify: + { + if (event->xdestroywindow.event == display->screen->xroot) + meta_stack_tracker_destroy_event (display->screen->stack_tracker, + &event->xdestroywindow); + } + if (window) + { + /* FIXME: It sucks that DestroyNotify events don't come with + * a timestamp; could we do something better here? Maybe X + * will change one day? + */ + guint32 timestamp; + timestamp = meta_display_get_current_time_roundtrip (display); + + if (display->grab_op != META_GRAB_OP_NONE && + display->grab_window == window) + meta_display_end_grab_op (display, timestamp); + + if (frame_was_receiver) + { + meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n", + window->frame->xwindow); + meta_error_trap_push (display); + meta_window_destroy_frame (window->frame->window); + meta_error_trap_pop (display); + } + else + { + /* Unmanage destroyed window */ + meta_window_unmanage (window, timestamp); + window = NULL; + } + } + break; + case UnmapNotify: + if (window) + { + /* FIXME: It sucks that UnmapNotify events don't come with + * a timestamp; could we do something better here? Maybe X + * will change one day? + */ + guint32 timestamp; + timestamp = meta_display_get_current_time_roundtrip (display); + + if (display->grab_op != META_GRAB_OP_NONE && + display->grab_window == window && + window->frame == NULL) + meta_display_end_grab_op (display, timestamp); + + if (!frame_was_receiver) + { + if (window->unmaps_pending == 0) + { + meta_topic (META_DEBUG_WINDOW_STATE, + "Window %s withdrawn\n", + window->desc); + + /* Unmanage withdrawn window */ + window->withdrawn = TRUE; + meta_window_unmanage (window, timestamp); + window = NULL; + } + else + { + window->unmaps_pending -= 1; + meta_topic (META_DEBUG_WINDOW_STATE, + "Received pending unmap, %d now pending\n", + window->unmaps_pending); + } + } + } + break; + case MapNotify: + /* NB: override redirect windows wont cause a map request so we + * watch out for map notifies against any root windows too if a + * compositor is enabled: */ + if (window == NULL && event->xmap.event == display->screen->xroot) + { + window = meta_window_x11_new (display, event->xmap.window, + FALSE, META_COMP_EFFECT_CREATE); + } + break; + case MapRequest: + if (window == NULL) + { + window = meta_window_x11_new (display, event->xmaprequest.window, + FALSE, META_COMP_EFFECT_CREATE); + } + /* if frame was receiver it's some malicious send event or something */ + else if (!frame_was_receiver && window) + { + meta_verbose ("MapRequest on %s mapped = %d minimized = %d\n", + window->desc, window->mapped, window->minimized); + if (window->minimized) + { + meta_window_unminimize (window); + if (window->workspace != window->screen->active_workspace) + { + meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n", + window->mapped, window->minimized); + meta_window_change_workspace (window, + window->screen->active_workspace); + } + } + } + break; + case ReparentNotify: + { + if (event->xreparent.event == display->screen->xroot) + meta_stack_tracker_reparent_event (display->screen->stack_tracker, + &event->xreparent); + } + break; + case ConfigureNotify: + if (event->xconfigure.event != event->xconfigure.window) + { + if (event->xconfigure.event == display->screen->xroot) + meta_stack_tracker_configure_event (display->screen->stack_tracker, + &event->xconfigure); + } + + if (window && window->override_redirect) + meta_window_x11_configure_notify (window, &event->xconfigure); + + break; + case ConfigureRequest: + /* This comment and code is found in both twm and fvwm */ + /* + * According to the July 27, 1988 ICCCM draft, we should ignore size and + * position fields in the WM_NORMAL_HINTS property when we map a window. + * Instead, we'll read the current geometry. Therefore, we should respond + * to configuration requests for windows which have never been mapped. + */ + if (window == NULL) + { + unsigned int xwcm; + XWindowChanges xwc; + + xwcm = event->xconfigurerequest.value_mask & + (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); + + xwc.x = event->xconfigurerequest.x; + xwc.y = event->xconfigurerequest.y; + xwc.width = event->xconfigurerequest.width; + xwc.height = event->xconfigurerequest.height; + xwc.border_width = event->xconfigurerequest.border_width; + + meta_verbose ("Configuring withdrawn window to %d,%d %dx%d border %d (some values may not be in mask)\n", + xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width); + meta_error_trap_push (display); + XConfigureWindow (display->xdisplay, event->xconfigurerequest.window, + xwcm, &xwc); + meta_error_trap_pop (display); + } + else + { + if (!frame_was_receiver) + meta_window_x11_configure_request (window, event); + } + break; + case GravityNotify: + break; + case ResizeRequest: + break; + case CirculateNotify: + break; + case CirculateRequest: + break; + case PropertyNotify: + { + MetaGroup *group; + + if (window && !frame_was_receiver) + meta_window_x11_property_notify (window, event); + else if (property_for_window && !frame_was_receiver) + meta_window_x11_property_notify (property_for_window, event); + + group = meta_display_lookup_group (display, + event->xproperty.window); + if (group != NULL) + meta_group_property_notify (group, event); + + if (event->xproperty.window == display->screen->xroot) + { + if (event->xproperty.atom == + display->atom__NET_DESKTOP_LAYOUT) + meta_screen_update_workspace_layout (display->screen); + else if (event->xproperty.atom == + display->atom__NET_DESKTOP_NAMES) + meta_screen_update_workspace_names (display->screen); + else if (meta_is_wayland_compositor () && + event->xproperty.atom == + display->atom__XKB_RULES_NAMES) + reload_xkb_rules (display->screen); +#if 0 + else if (event->xproperty.atom == + display->atom__NET_RESTACK_WINDOW) + handle_net_restack_window (display, event); +#endif + + /* we just use this property as a sentinel to avoid + * certain race conditions. See the comment for the + * sentinel_counter variable declaration in display.h + */ + if (event->xproperty.atom == + display->atom__MUTTER_SENTINEL) + { + meta_display_decrement_focus_sentinel (display); + } + } + } + break; + case SelectionClear: + /* do this here instead of at end of function + * so we can return + */ + + /* FIXME: Clearing display->current_time here makes no sense to + * me; who put this here and why? + */ + display->current_time = CurrentTime; + + process_selection_clear (display, event); + /* Note that processing that may have resulted in + * closing the display... so return right away. + */ + return FALSE; + case SelectionRequest: + process_selection_request (display, event); + break; + case SelectionNotify: + break; + case ColormapNotify: + break; + case ClientMessage: + if (window) + { + if (event->xclient.message_type == display->atom_WL_SURFACE_ID) + { + guint32 surface_id = event->xclient.data.l[0]; + meta_xwayland_handle_wl_surface_id (window, surface_id); + } + else if (!frame_was_receiver) + meta_window_x11_client_message (window, event); + } + else + { + if (event->xclient.window == display->screen->xroot) + { + if (event->xclient.message_type == + display->atom__NET_CURRENT_DESKTOP) + { + int space; + MetaWorkspace *workspace; + guint32 time; + + space = event->xclient.data.l[0]; + time = event->xclient.data.l[1]; + + meta_verbose ("Request to change current workspace to %d with " + "specified timestamp of %u\n", + space, time); + + workspace = meta_screen_get_workspace_by_index (display->screen, space); + + /* Handle clients using the older version of the spec... */ + if (time == 0 && workspace) + { + meta_warning ("Received a NET_CURRENT_DESKTOP message " + "from a broken (outdated) client who sent " + "a 0 timestamp\n"); + time = meta_display_get_current_time_roundtrip (display); + } + + if (workspace) + meta_workspace_activate (workspace, time); + else + meta_verbose ("Don't know about workspace %d\n", space); + } + else if (event->xclient.message_type == + display->atom__NET_NUMBER_OF_DESKTOPS) + { + int num_spaces; + + num_spaces = event->xclient.data.l[0]; + + meta_verbose ("Request to set number of workspaces to %d\n", + num_spaces); + + meta_prefs_set_num_workspaces (num_spaces); + } + else if (event->xclient.message_type == + display->atom__NET_SHOWING_DESKTOP) + { + gboolean showing_desktop; + guint32 timestamp; + + showing_desktop = event->xclient.data.l[0] != 0; + /* FIXME: Braindead protocol doesn't have a timestamp */ + timestamp = meta_display_get_current_time_roundtrip (display); + meta_verbose ("Request to %s desktop\n", + showing_desktop ? "show" : "hide"); + + if (showing_desktop) + meta_screen_show_desktop (display->screen, timestamp); + else + { + meta_screen_unshow_desktop (display->screen); + meta_workspace_focus_default_window (display->screen->active_workspace, NULL, timestamp); + } + } + else if (event->xclient.message_type == + display->atom_WM_PROTOCOLS) + { + meta_verbose ("Received WM_PROTOCOLS message\n"); + + if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING) + { + guint32 timestamp = event->xclient.data.l[1]; + + meta_display_pong_for_serial (display, timestamp); + + /* We don't want ping reply events going into + * the GTK+ event loop because gtk+ will treat + * them as ping requests and send more replies. + */ + bypass_gtk = TRUE; + } + } + } + + if (event->xclient.message_type == + display->atom__NET_REQUEST_FRAME_EXTENTS) + { + meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message\n"); + process_request_frame_extents (display, event); + } + } + break; + case MappingNotify: + { + gboolean ignore_current; + + ignore_current = FALSE; + + /* Check whether the next event is an identical MappingNotify + * event. If it is, ignore the current event, we'll update + * when we get the next one. + */ + if (XPending (display->xdisplay)) + { + XEvent next_event; + + XPeekEvent (display->xdisplay, &next_event); + + if (next_event.type == MappingNotify && + next_event.xmapping.request == event->xmapping.request) + ignore_current = TRUE; + } + + if (!ignore_current) + { + /* Let XLib know that there is a new keyboard mapping. + */ + XRefreshKeyboardMapping (&event->xmapping); + meta_display_process_mapping_event (display, event); + } + } + break; + default: +#ifdef HAVE_XKB + if (event->type == display->xkb_base_event_type) + { + XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event; + + switch (xkb_ev->xkb_type) + { + case XkbBellNotify: + if (XSERVER_TIME_IS_BEFORE(display->last_bell_time, + xkb_ev->time - 100)) + { + display->last_bell_time = xkb_ev->time; + meta_bell_notify (display, xkb_ev); + } + break; + case XkbNewKeyboardNotify: + case XkbMapNotify: + if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID) + meta_display_process_mapping_event (display, event); + break; + } + } +#endif + break; + } + + out: + return bypass_gtk; +} + +static gboolean +grab_op_should_block_mouse_events (MetaGrabOp op) +{ + switch (op) + { + case META_GRAB_OP_WAYLAND_CLIENT: + case META_GRAB_OP_COMPOSITOR: + return TRUE; + + default: + return FALSE; + } +} + +static gboolean +window_has_xwindow (MetaWindow *window, + Window xwindow) +{ + if (window->xwindow == xwindow) + return TRUE; + + if (window->frame && window->frame->xwindow == xwindow) + return TRUE; + + return FALSE; +} + +/** + * meta_display_handle_xevent: + * @display: The MetaDisplay that events are coming from + * @event: The event that just happened + * + * This is the most important function in the whole program. It is the heart, + * it is the nexus, it is the Grand Central Station of Mutter's world. + * When we create a #MetaDisplay, we ask GDK to pass *all* events for *all* + * windows to this function. So every time anything happens that we might + * want to know about, this function gets called. You see why it gets a bit + * busy around here. Most of this function is a ginormous switch statement + * dealing with all the kinds of events that might turn up. + */ +static gboolean +meta_display_handle_xevent (MetaDisplay *display, + XEvent *event) +{ + Window modified; + gboolean bypass_compositor = FALSE, bypass_gtk = FALSE; + XIEvent *input_event; + MetaMonitorManager *monitor; + +#if 0 + meta_spew_event (display, event); +#endif + +#ifdef HAVE_STARTUP_NOTIFICATION + if (sn_display_process_event (display->sn_display, event)) + { + bypass_gtk = bypass_compositor = TRUE; + goto out; + } +#endif + + /* Intercept XRandR events early and don't attempt any + processing for them. We still let them through to Gdk though, + so it can update its own internal state. + */ + monitor = meta_monitor_manager_get (); + if (meta_monitor_manager_handle_xevent (monitor, event)) + { + bypass_compositor = TRUE; + goto out; + } + + display->current_time = event_get_time (display, event); + display->monitor_cache_invalidated = TRUE; + + if (display->focused_by_us && + event->xany.serial > display->focus_serial && + display->focus_window && + !window_has_xwindow (display->focus_window, display->server_focus_window)) + { + meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed\n", + display->focus_window->desc); + meta_display_update_focus_window (display, + meta_display_lookup_x_window (display, display->server_focus_window), + display->server_focus_window, + display->server_focus_serial, + FALSE); + } + + if (event->xany.window == display->screen->xroot) + { + if (meta_screen_handle_xevent (display->screen, event)) + { + bypass_gtk = bypass_compositor = TRUE; + goto out; + } + } + + modified = event_get_modified_window (display, event); + + input_event = get_input_event (display, event); + + if (event->type == UnmapNotify) + { + if (meta_ui_window_should_not_cause_focus (display->xdisplay, + modified)) + { + meta_display_add_ignored_crossing_serial (display, event->xany.serial); + meta_topic (META_DEBUG_FOCUS, + "Adding EnterNotify serial %lu to ignored focus serials\n", + event->xany.serial); + } + } + else if (input_event && + input_event->evtype == XI_Leave && + ((XILeaveEvent *)input_event)->mode == XINotifyUngrab && + modified == display->ungrab_should_not_cause_focus_window) + { + meta_display_add_ignored_crossing_serial (display, event->xany.serial); + meta_topic (META_DEBUG_FOCUS, + "Adding LeaveNotify serial %lu to ignored focus serials\n", + event->xany.serial); + } + +#ifdef HAVE_XI23 + if (meta_display_process_barrier_event (display, input_event)) + { + bypass_gtk = bypass_compositor = TRUE; + goto out; + } +#endif /* HAVE_XI23 */ + + /* libXi does not properly copy the serial to XI2 events, so pull it + * from the parent XAnyEvent and pass it to handle_input_xevent. + * See: https://bugs.freedesktop.org/show_bug.cgi?id=64687 + */ + if (handle_input_xevent (display, input_event, event->xany.serial)) + { + bypass_gtk = bypass_compositor = TRUE; + goto out; + } + + if (handle_other_xevent (display, event)) + { + bypass_gtk = TRUE; + goto out; + } + + out: + if (!bypass_compositor) + { + MetaWindow *window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL; + + if (meta_compositor_process_event (display->compositor, event, window)) + bypass_gtk = TRUE; + } + + display->current_time = CurrentTime; + return bypass_gtk; +} + +static void +handle_idletime_for_event (const ClutterEvent *event) +{ + ClutterInputDevice *device, *source_device; + MetaIdleMonitor *core_monitor, *device_monitor; + int device_id; + + /* This is handled by XSync under X11. */ + if (!meta_is_wayland_compositor ()) + return; + + device = clutter_event_get_device (event); + if (device == NULL) + return; + + device_id = clutter_input_device_get_device_id (device); + + core_monitor = meta_idle_monitor_get_core (); + device_monitor = meta_idle_monitor_get_for_device (device_id); + + meta_idle_monitor_native_reset_idletime (core_monitor); + meta_idle_monitor_native_reset_idletime (device_monitor); + + source_device = clutter_event_get_source_device (event); + if (source_device != device) + { + device_id = clutter_input_device_get_device_id (device); + device_monitor = meta_idle_monitor_get_for_device (device_id); + meta_idle_monitor_native_reset_idletime (device_monitor); + } +} + +static gboolean +meta_display_handle_event (MetaDisplay *display, + const ClutterEvent *event) +{ + MetaWindow *window; + gboolean bypass_clutter = FALSE, bypass_wayland = FALSE; + MetaWaylandCompositor *compositor = NULL; + + if (meta_is_wayland_compositor ()) + { + compositor = meta_wayland_compositor_get_default (); + meta_wayland_compositor_update (compositor, event); + } + + handle_idletime_for_event (event); + + window = get_window_for_event (display, event); + + display->current_time = event->any.time; + + if (window && !window->override_redirect && + (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_BUTTON_PRESS)) + { + if (CurrentTime == display->current_time) + { + /* We can't use missing (i.e. invalid) timestamps to set user time, + * nor do we want to use them to sanity check other timestamps. + * See bug 313490 for more details. + */ + meta_warning ("Event has no timestamp! You may be using a broken " + "program such as xse. Please ask the authors of that " + "program to fix it.\n"); + } + else + { + meta_window_set_user_time (window, display->current_time); + meta_display_sanity_check_timestamps (display, display->current_time); + } + } + + switch (event->type) + { + case CLUTTER_BUTTON_PRESS: + if (grab_op_should_block_mouse_events (display->grab_op)) + break; + + display->overlay_key_only_pressed = FALSE; + + if ((window && + meta_grab_op_is_mouse (display->grab_op) && + (event->button.modifier_state & display->window_grab_modifiers) && + display->grab_button != (int) event->button.button && + display->grab_window == window) || + meta_grab_op_is_keyboard (display->grab_op)) + { + meta_topic (META_DEBUG_WINDOW_OPS, + "Ending grab op %u on window %s due to button press\n", + display->grab_op, + (display->grab_window ? + display->grab_window->desc : + "none")); + meta_display_end_grab_op (display, event->any.time); + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + else if (window && display->grab_op == META_GRAB_OP_NONE) + { + ClutterModifierType grab_mask; + gboolean unmodified; + gboolean fully_modified; + + grab_mask = display->window_grab_modifiers; + if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS")) + grab_mask |= CLUTTER_CONTROL_MASK; + + /* We have three passive button grabs: + * - on any button, without modifiers => focuses and maybe raises the window + * - on resize button, with modifiers => start an interactive resizing + * (normally <Super>middle) + * - on move button, with modifiers => start an interactive move + * (normally <Super>left) + * - on menu button, with modifiers => show the window menu + * (normally <Super>right) + * + * We may get here because we actually have a button + * grab on the window, or because we're a wayland + * compositor and thus we see all the events, so we + * need to check if the event is interesting. + * We want an event that is not modified, for a window + * that has (or would have, the wayland case) the + * button grab active. + * + * We may have other events on the window, for example + * a click on a frame button, but that's not for us to + * care about. Just let the event through. + */ + unmodified = (event->button.modifier_state & grab_mask) == 0; + fully_modified = grab_mask && (event->button.modifier_state & grab_mask) == grab_mask; + + if (unmodified && window && window->have_focus_click_grab) + { + if (meta_prefs_get_raise_on_click ()) + meta_window_raise (window); + else + meta_topic (META_DEBUG_FOCUS, + "Not raising window on click due to don't-raise-on-click option\n"); + + /* Don't focus panels--they must explicitly request focus. + * See bug 160470 + */ + if (window->type != META_WINDOW_DOCK) + { + meta_topic (META_DEBUG_FOCUS, + "Focusing %s due to unmodified button %u press (display.c)\n", + window->desc, event->button.button); + meta_window_focus (window, event->any.time); + } + else + /* However, do allow terminals to lose focus due to new + * window mappings after the user clicks on a panel. + */ + display->allow_terminal_deactivation = TRUE; + + meta_verbose ("Allowing events time %u\n", + (unsigned int)event->button.time); + + XIAllowEvents (display->xdisplay, clutter_input_device_get_device_id (event->button.device), + XIReplayDevice, event->button.time); + bypass_clutter = TRUE; + } + else if (fully_modified && (int) event->button.button == meta_prefs_get_mouse_button_resize ()) + { + if (window->has_resize_func) + { + gboolean north, south; + gboolean west, east; + MetaRectangle frame_rect; + MetaGrabOp op; + + meta_window_get_frame_rect (window, &frame_rect); + + west = event->button.x < (frame_rect.x + 1 * frame_rect.width / 3); + east = event->button.x > (frame_rect.x + 2 * frame_rect.width / 3); + north = event->button.y < (frame_rect.y + 1 * frame_rect.height / 3); + south = event->button.y > (frame_rect.y + 2 * frame_rect.height / 3); + + if (north && west) + op = META_GRAB_OP_RESIZING_NW; + else if (north && east) + op = META_GRAB_OP_RESIZING_NE; + else if (south && west) + op = META_GRAB_OP_RESIZING_SW; + else if (south && east) + op = META_GRAB_OP_RESIZING_SE; + else if (north) + op = META_GRAB_OP_RESIZING_N; + else if (west) + op = META_GRAB_OP_RESIZING_W; + else if (east) + op = META_GRAB_OP_RESIZING_E; + else if (south) + op = META_GRAB_OP_RESIZING_S; + else /* Middle region is no-op to avoid user triggering wrong action */ + op = META_GRAB_OP_NONE; + + if (op != META_GRAB_OP_NONE) + meta_display_begin_grab_op (display, + window->screen, + window, + op, + TRUE, + FALSE, + event->button.button, + 0, + event->any.time, + event->button.x, + event->button.y); + } + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + else if (fully_modified && (int) event->button.button == meta_prefs_get_mouse_button_menu ()) + { + if (meta_prefs_get_raise_on_click ()) + meta_window_raise (window); + meta_window_show_menu (window, + event->button.x, + event->button.y, + event->button.button, + event->any.time); + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + else if (fully_modified && (int) event->button.button == 1) + { + if (window->has_move_func) + { + meta_display_begin_grab_op (display, + window->screen, + window, + META_GRAB_OP_MOVING, + TRUE, + FALSE, + event->button.button, + 0, + event->any.time, + event->button.x, + event->button.y); + } + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + } + break; + case CLUTTER_BUTTON_RELEASE: + if (grab_op_should_block_mouse_events (display->grab_op)) + break; + + display->overlay_key_only_pressed = FALSE; + + if (display->grab_window == window && + meta_grab_op_is_mouse (display->grab_op)) + { + meta_window_handle_mouse_grab_op_event (window, event); + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + break; + case CLUTTER_MOTION: + if (grab_op_should_block_mouse_events (display->grab_op)) + break; + + if (display->grab_window == window && + meta_grab_op_is_mouse (display->grab_op)) + { + meta_window_handle_mouse_grab_op_event (window, event); + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + break; + + case CLUTTER_KEY_PRESS: + case CLUTTER_KEY_RELEASE: + /* For key events, it's important to enforce single-handling, or + * we can get into a confused state. So if a keybinding is + * handled (because it's one of our hot-keys, or because we are + * in a keyboard-grabbed mode like moving a window, we don't + * want to pass the key event to the compositor or Wayland at all. + */ + if (meta_display_process_key_event (display, window, (ClutterKeyEvent *) event)) + { + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + + default: + break; + } + + /* If the compositor has a grab, don't pass that through to Wayland */ + if (display->grab_op == META_GRAB_OP_COMPOSITOR) + bypass_wayland = TRUE; + + /* If a Wayland client has a grab, don't pass that through to Clutter */ + if (display->grab_op == META_GRAB_OP_WAYLAND_CLIENT) + bypass_clutter = TRUE; + + if (compositor && !bypass_wayland) + { + if (meta_wayland_compositor_handle_event (compositor, event)) + bypass_clutter = TRUE; + } + + return bypass_clutter; +} + +static GdkFilterReturn +xevent_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + MetaDisplay *display = data; + + if (meta_display_handle_xevent (display, xevent)) + return GDK_FILTER_REMOVE; + else + return GDK_FILTER_CONTINUE; +} + +static gboolean +event_callback (const ClutterEvent *event, + gpointer data) +{ + MetaDisplay *display = data; + + return meta_display_handle_event (display, event); +} + +void +meta_display_init_events (MetaDisplay *display) +{ + gdk_window_add_filter (NULL, xevent_filter, display); + display->clutter_event_filter = clutter_event_add_filter (NULL, + event_callback, + NULL, + display); +} + +void +meta_display_free_events (MetaDisplay *display) +{ + gdk_window_remove_filter (NULL, xevent_filter, display); + clutter_event_remove_filter (display->clutter_event_filter); + display->clutter_event_filter = 0; +} diff --git a/src/core/meta-cursor-tracker-private.h b/src/core/events.h index 55c09c4..66a34ca 100644 --- a/src/core/meta-cursor-tracker-private.h +++ b/src/core/events.h @@ -1,7 +1,10 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* - * Copyright (C) 2013 Red Hat, Inc. + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. + * Copyright (C) 2003, 2004 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,18 +18,15 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - * Author: Giovanni Campagna <gcampagn@redhat.com> */ -#ifndef META_CURSOR_TRACKER_PRIVATE_H -#define META_CURSOR_TRACKER_PRIVATE_H +#include <meta/display.h> -#include <meta/meta-cursor-tracker.h> +#ifndef META_EVENTS_H +#define META_EVENTS_H -gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, - XEvent *xevent); +void meta_display_init_events (MetaDisplay *display); +void meta_display_free_events (MetaDisplay *display); -void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, - MetaCursor cursor); #endif + diff --git a/src/core/frame.c b/src/core/frame.c index ed7e3cb..350493c 100644 --- a/src/core/frame.c +++ b/src/core/frame.c @@ -35,8 +35,7 @@ ButtonPressMask | ButtonReleaseMask | \ PointerMotionMask | PointerMotionHintMask | \ EnterWindowMask | LeaveWindowMask | \ - FocusChangeMask | \ - ColormapChangeMask) + FocusChangeMask) void meta_window_ensure_frame (MetaWindow *window) @@ -45,6 +44,7 @@ meta_window_ensure_frame (MetaWindow *window) XSetWindowAttributes attrs; Visual *visual; gulong create_serial; + MetaStackWindow stack_window; if (window->frame) return; @@ -100,8 +100,10 @@ meta_window_ensure_frame (MetaWindow *window) frame->rect.height, frame->window->screen->number, &create_serial); + stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_window.x11.xwindow = frame->xwindow; meta_stack_tracker_record_add (window->screen->stack_tracker, - frame->xwindow, + &stack_window, create_serial); meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow); @@ -125,8 +127,9 @@ meta_window_ensure_frame (MetaWindow *window) window->rect.x = 0; window->rect.y = 0; + stack_window.x11.xwindow = window->xwindow; meta_stack_tracker_record_remove (window->screen->stack_tracker, - window->xwindow, + &stack_window, XNextRequest (window->display->xdisplay)); XReparentWindow (window->display->xdisplay, window->xwindow, @@ -161,6 +164,7 @@ meta_window_destroy_frame (MetaWindow *window) { MetaFrame *frame; MetaFrameBorders borders; + MetaStackWindow stack_window; if (window->frame == NULL) return; @@ -187,8 +191,10 @@ meta_window_destroy_frame (MetaWindow *window) "Incrementing unmaps_pending on %s for reparent back to root\n", window->desc); window->unmaps_pending += 1; } + stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_window.x11.xwindow = window->xwindow; meta_stack_tracker_record_add (window->screen->stack_tracker, - window->xwindow, + &stack_window, XNextRequest (window->display->xdisplay)); XReparentWindow (window->display->xdisplay, window->xwindow, diff --git a/src/core/keybindings-private.h b/src/core/keybindings-private.h index ffc40f1..15c1700 100644 --- a/src/core/keybindings-private.h +++ b/src/core/keybindings-private.h @@ -104,9 +104,9 @@ gboolean meta_window_grab_all_keys (MetaWindow *window, guint32 timestamp); void meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp); -gboolean meta_display_process_key_event (MetaDisplay *display, - MetaWindow *window, - XIDeviceEvent *event); +gboolean meta_display_process_key_event (MetaDisplay *display, + MetaWindow *window, + ClutterKeyEvent *event); void meta_display_process_mapping_event (MetaDisplay *display, XEvent *event); @@ -122,7 +122,3 @@ void meta_prefs_get_overlay_binding (MetaKeyCombo *combo); const char *meta_prefs_get_iso_next_group_option (void); #endif - - - - diff --git a/src/core/keybindings.c b/src/core/keybindings.c index 83b2f70..8aa247a 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -28,7 +28,6 @@ */ #define _GNU_SOURCE -#define _XOPEN_SOURCE /* for putenv() */ #include <config.h> #include "keybindings-private.h" @@ -42,18 +41,26 @@ #include "screen-private.h" #include <meta/prefs.h> #include "util-private.h" +#include "meta-accel-parse.h" -#include <X11/keysym.h> #include <string.h> #include <stdio.h> #include <stdlib.h> +#include <linux/input.h> + +#include <xkbcommon/xkbcommon.h> + #ifdef HAVE_XKB #include <X11/XKBlib.h> #endif +#include "wayland/meta-wayland.h" +#include "meta-backend.h" + #define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings" #define SCHEMA_MUTTER_KEYBINDINGS "org.gnome.mutter.keybindings" +#define SCHEMA_MUTTER_WAYLAND_KEYBINDINGS "org.gnome.mutter.wayland.keybindings" static gboolean add_builtin_keybinding (MetaDisplay *display, const char *name, @@ -109,23 +116,20 @@ meta_key_binding_is_builtin (MetaKeyBinding *binding) * handler functions and have some kind of flag to say they're unbindable. */ -static gboolean process_mouse_move_resize_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym); +static gboolean process_mouse_move_resize_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event); -static gboolean process_keyboard_move_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym); +static gboolean process_keyboard_move_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event); -static gboolean process_keyboard_resize_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym); +static gboolean process_keyboard_resize_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event); static void grab_key_bindings (MetaDisplay *display); static void ungrab_key_bindings (MetaDisplay *display); @@ -182,10 +186,6 @@ reload_keymap (MetaDisplay *display) if (display->keymap) meta_XFree (display->keymap); - /* This is expensive to compute, so we'll lazily load if and when we first - * need it */ - display->above_tab_keycode = 0; - display->keymap = XGetKeyboardMapping (display->xdisplay, display->min_keycode, display->max_keycode - @@ -193,24 +193,27 @@ reload_keymap (MetaDisplay *display) &display->keysyms_per_keycode); } +static const char * +keysym_name (xkb_keysym_t keysym) +{ + static char name[32] = ""; + xkb_keysym_get_name (keysym, name, sizeof (name)); + return name; +} + static void reload_modmap (MetaDisplay *display) { XModifierKeymap *modmap; int map_size; int i; - - if (display->modmap) - XFreeModifiermap (display->modmap); + int num_lock_mask = 0; + int scroll_lock_mask = 0; modmap = XGetModifierMapping (display->xdisplay); - display->modmap = modmap; - display->ignored_modifier_mask = 0; /* Multiple bits may get set in each of these */ - display->num_lock_mask = 0; - display->scroll_lock_mask = 0; display->meta_mask = 0; display->hyper_mask = 0; display->super_mask = 0; @@ -238,40 +241,37 @@ reload_modmap (MetaDisplay *display) { if (syms[j] != 0) { - const char *str; - - str = XKeysymToString (syms[j]); meta_topic (META_DEBUG_KEYBINDINGS, "Keysym %s bound to modifier 0x%x\n", - str ? str : "none", + keysym_name (syms[j]), (1 << ( i / modmap->max_keypermod))); } - if (syms[j] == XK_Num_Lock) + if (syms[j] == XKB_KEY_Num_Lock) { /* Mod1Mask is 1 << 3 for example, i.e. the * fourth modifier, i / keyspermod is the modifier * index */ - display->num_lock_mask |= (1 << ( i / modmap->max_keypermod)); + num_lock_mask |= (1 << ( i / modmap->max_keypermod)); } - else if (syms[j] == XK_Scroll_Lock) + else if (syms[j] == XKB_KEY_Scroll_Lock) { - display->scroll_lock_mask |= (1 << ( i / modmap->max_keypermod)); + scroll_lock_mask |= (1 << ( i / modmap->max_keypermod)); } - else if (syms[j] == XK_Super_L || - syms[j] == XK_Super_R) + else if (syms[j] == XKB_KEY_Super_L || + syms[j] == XKB_KEY_Super_R) { display->super_mask |= (1 << ( i / modmap->max_keypermod)); } - else if (syms[j] == XK_Hyper_L || - syms[j] == XK_Hyper_R) + else if (syms[j] == XKB_KEY_Hyper_L || + syms[j] == XKB_KEY_Hyper_R) { display->hyper_mask |= (1 << ( i / modmap->max_keypermod)); } - else if (syms[j] == XK_Meta_L || - syms[j] == XK_Meta_R) + else if (syms[j] == XKB_KEY_Meta_L || + syms[j] == XKB_KEY_Meta_R) { display->meta_mask |= (1 << ( i / modmap->max_keypermod)); } @@ -283,18 +283,20 @@ reload_modmap (MetaDisplay *display) ++i; } - display->ignored_modifier_mask = (display->num_lock_mask | - display->scroll_lock_mask | + display->ignored_modifier_mask = (num_lock_mask | + scroll_lock_mask | LockMask); meta_topic (META_DEBUG_KEYBINDINGS, "Ignoring modmask 0x%x num lock 0x%x scroll lock 0x%x hyper 0x%x super 0x%x meta 0x%x\n", display->ignored_modifier_mask, - display->num_lock_mask, - display->scroll_lock_mask, + num_lock_mask, + scroll_lock_mask, display->hyper_mask, display->super_mask, display->meta_mask); + + XFreeModifiermap (modmap); } /* Original code from gdk_x11_keymap_get_entries_for_keyval() in @@ -310,6 +312,14 @@ get_keycodes_for_keysym (MetaDisplay *display, retval = g_array_new (FALSE, FALSE, sizeof (int)); + /* Special-case: Fake mutter keysym */ + if (keysym == META_KEY_ABOVE_TAB) + { + keycode = KEY_GRAVE + 8; + g_array_append_val (retval, keycode); + goto out; + } + keycode = display->min_keycode; while (keycode <= display->max_keycode) { @@ -327,12 +337,31 @@ get_keycodes_for_keysym (MetaDisplay *display, ++keycode; } + out: n_keycodes = retval->len; *keycodes = (int*) g_array_free (retval, n_keycodes == 0 ? TRUE : FALSE); - return n_keycodes; } +static guint +get_first_keycode_for_keysym (MetaDisplay *display, + guint keysym) +{ + int *keycodes; + int n_keycodes; + int keycode; + + n_keycodes = get_keycodes_for_keysym (display, keysym, &keycodes); + + if (n_keycodes > 0) + keycode = keycodes[0]; + else + keycode = 0; + + g_free (keycodes); + return keycode; +} + static void reload_iso_next_group_combos (MetaDisplay *display) { @@ -350,7 +379,7 @@ reload_iso_next_group_combos (MetaDisplay *display) if (iso_next_group_option == NULL) return; - n_keycodes = get_keycodes_for_keysym (display, XK_ISO_Next_Group, &keycodes); + n_keycodes = get_keycodes_for_keysym (display, XKB_KEY_ISO_Next_Group, &keycodes); if (g_str_equal (iso_next_group_option, "toggle") || g_str_equal (iso_next_group_option, "lalt_toggle") || @@ -369,7 +398,7 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = 0; } @@ -382,7 +411,7 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = ShiftMask; } @@ -395,7 +424,7 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = Mod1Mask; } @@ -409,11 +438,11 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = ShiftMask; - combos[i + n_keycodes].keysym = XK_ISO_Next_Group; + combos[i + n_keycodes].keysym = XKB_KEY_ISO_Next_Group; combos[i + n_keycodes].keycode = keycodes[i]; combos[i + n_keycodes].modifiers = ControlMask; } @@ -425,11 +454,11 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = Mod1Mask; - combos[i + n_keycodes].keysym = XK_ISO_Next_Group; + combos[i + n_keycodes].keysym = XKB_KEY_ISO_Next_Group; combos[i + n_keycodes].keycode = keycodes[i]; combos[i + n_keycodes].modifiers = ControlMask; } @@ -442,11 +471,11 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = Mod1Mask; - combos[i + n_keycodes].keysym = XK_ISO_Next_Group; + combos[i + n_keycodes].keysym = XKB_KEY_ISO_Next_Group; combos[i + n_keycodes].keycode = keycodes[i]; combos[i + n_keycodes].modifiers = ShiftMask; } @@ -463,16 +492,6 @@ reload_iso_next_group_combos (MetaDisplay *display) display->iso_next_group_combos = combos; } -static guint -keysym_to_keycode (MetaDisplay *display, - guint keysym) -{ - if (keysym == META_KEY_ABOVE_TAB) - return meta_display_get_above_tab_keycode (display); - else - return XKeysymToKeycode (display->xdisplay, keysym); -} - static void binding_reload_keycode_foreach (gpointer key, gpointer value, @@ -482,7 +501,7 @@ binding_reload_keycode_foreach (gpointer key, MetaKeyBinding *binding = value; if (binding->keysym) - binding->keycode = keysym_to_keycode (display, binding->keysym); + binding->keycode = get_first_keycode_for_keysym (display, binding->keysym); } static void @@ -494,7 +513,7 @@ reload_keycodes (MetaDisplay *display) if (display->overlay_key_combo.keysym != 0) { display->overlay_key_combo.keycode = - keysym_to_keycode (display, display->overlay_key_combo.keysym); + get_first_keycode_for_keysym (display, display->overlay_key_combo.keysym); } else { @@ -686,15 +705,7 @@ ungrab_key_bindings (MetaDisplay *display) meta_error_trap_push (display); /* for efficiency push outer trap */ - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_screen_ungrab_keys (screen); - - tmp = tmp->next; - } + meta_screen_ungrab_keys (display->screen); windows = meta_display_list_windows (display, META_LIST_DEFAULT); tmp = windows; @@ -719,15 +730,7 @@ grab_key_bindings (MetaDisplay *display) meta_error_trap_push (display); /* for efficiency push outer trap */ - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_screen_grab_keys (screen); - - tmp = tmp->next; - } + meta_screen_grab_keys (display->screen); windows = meta_display_list_windows (display, META_LIST_DEFAULT); tmp = windows; @@ -758,7 +761,8 @@ display_get_keybinding (MetaDisplay *display, } static guint -next_dynamic_keybinding_action () { +next_dynamic_keybinding_action (void) +{ static guint num_dynamic_bindings = 0; return META_KEYBINDING_ACTION_LAST + (++num_dynamic_bindings); } @@ -1014,25 +1018,10 @@ meta_display_shutdown_keys (MetaDisplay *display) if (display->keymap) meta_XFree (display->keymap); - if (display->modmap) - XFreeModifiermap (display->modmap); - g_hash_table_destroy (display->key_bindings_index); g_hash_table_destroy (display->key_bindings); } -static const char* -keysym_name (int keysym) -{ - const char *name; - - name = XKeysymToString (keysym); - if (name == NULL) - name = "(unknown)"; - - return name; -} - /* Grab/ungrab, ignoring all annoying modifiers like NumLock etc. */ static void meta_change_keygrab (MetaDisplay *display, @@ -1081,7 +1070,7 @@ meta_change_keygrab (MetaDisplay *display, mods = (XIGrabModifiers) { modmask | ignored_mask, 0 }; if (meta_is_debugging ()) - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); if (grab) XIGrabKeycode (display->xdisplay, META_VIRTUAL_CORE_KEYBOARD_ID, @@ -1102,7 +1091,7 @@ meta_change_keygrab (MetaDisplay *display, if (grab && result != Success) { if (result == BadAccess) - meta_warning (_("Some other program is already using the key %s with modifiers %x as a binding\n"), keysym_name (keysym), modmask | ignored_mask); + meta_warning ("Some other program is already using the key %s with modifiers %x as a binding\n", keysym_name (keysym), modmask | ignored_mask); else meta_topic (META_DEBUG_KEYBINDINGS, "Failed to grab key %s with modifiers %x\n", @@ -1275,17 +1264,17 @@ meta_window_ungrab_keys (MetaWindow *window) } static void -handle_external_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer user_data) +handle_external_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer user_data) { guint action = meta_display_get_keybinding_action (display, binding->keycode, binding->mask); - meta_display_accelerator_activate (display, action, event->deviceid, event->time); + meta_display_accelerator_activate (display, action, event); } @@ -1299,19 +1288,18 @@ meta_display_grab_accelerator (MetaDisplay *display, guint keycode = 0; guint mask = 0; MetaVirtualModifier modifiers = 0; - GSList *l; - if (!meta_ui_parse_accelerator (accelerator, &keysym, &keycode, &modifiers)) + if (!meta_parse_accelerator (accelerator, &keysym, &keycode, &modifiers)) { meta_topic (META_DEBUG_KEYBINDINGS, "Failed to parse accelerator\n"); - meta_warning (_("\"%s\" is not a valid accelerator\n"), accelerator); + meta_warning ("\"%s\" is not a valid accelerator\n", accelerator); return META_KEYBINDING_ACTION_NONE; } meta_display_devirtualize_modifiers (display, modifiers, &mask); - keycode = keysym_to_keycode (display, keysym); + keycode = get_first_keycode_for_keysym (display, keysym); if (keycode == 0) return META_KEYBINDING_ACTION_NONE; @@ -1319,11 +1307,7 @@ meta_display_grab_accelerator (MetaDisplay *display, if (display_get_keybinding (display, keycode, mask)) return META_KEYBINDING_ACTION_NONE; - for (l = display->screens; l; l = l->next) - { - MetaScreen *screen = l->data; - meta_change_keygrab (display, screen->xroot, TRUE, keysym, keycode, mask); - } + meta_change_keygrab (display, display->screen->xroot, TRUE, keysym, keycode, mask); grab = g_new0 (MetaKeyGrab, 1); grab->action = next_dynamic_keybinding_action (); @@ -1367,22 +1351,17 @@ meta_display_ungrab_accelerator (MetaDisplay *display, return FALSE; meta_display_devirtualize_modifiers (display, grab->combo->modifiers, &mask); - keycode = keysym_to_keycode (display, grab->combo->keysym); + keycode = get_first_keycode_for_keysym (display, grab->combo->keysym); binding = display_get_keybinding (display, keycode, mask); if (binding) { guint32 index_key; - GSList *l; - for (l = display->screens; l; l = l->next) - { - MetaScreen *screen = l->data; - meta_change_keygrab (display, screen->xroot, FALSE, - binding->keysym, - binding->keycode, - binding->mask); - } + meta_change_keygrab (display, display->screen->xroot, FALSE, + binding->keysym, + binding->keycode, + binding->mask); index_key = key_binding_key (binding->keycode, binding->mask); g_hash_table_remove (display->key_bindings_index, GINT_TO_POINTER (index_key)); @@ -1436,7 +1415,7 @@ grab_keyboard (MetaDisplay *display, /* Grab the keyboard, so we get key releases and all key * presses */ - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); /* Strictly, we only need to set grab_mode on the keyboard device * while the pointer should always be XIGrabModeAsync. Unfortunately @@ -1541,6 +1520,10 @@ meta_window_grab_all_keys (MetaWindow *window, Window grabwindow; gboolean retval; + /* We don't need to grab Wayland clients */ + if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) + return TRUE; + if (window->all_keys_grabbed) return FALSE; @@ -1613,38 +1596,37 @@ meta_display_unfreeze_keyboard (MetaDisplay *display, guint32 timestamp) } static gboolean -is_modifier (MetaDisplay *display, - unsigned int keycode) +is_modifier (xkb_keysym_t keysym) { - int i; - int map_size; - gboolean retval = FALSE; - - g_assert (display->modmap); - - map_size = 8 * display->modmap->max_keypermod; - i = 0; - while (i < map_size) + switch (keysym) { - if (keycode == display->modmap->modifiermap[i]) - { - retval = TRUE; - break; - } - ++i; + case XKB_KEY_Shift_L: + case XKB_KEY_Shift_R: + case XKB_KEY_Control_L: + case XKB_KEY_Control_R: + case XKB_KEY_Caps_Lock: + case XKB_KEY_Shift_Lock: + case XKB_KEY_Meta_L: + case XKB_KEY_Meta_R: + case XKB_KEY_Alt_L: + case XKB_KEY_Alt_R: + case XKB_KEY_Super_L: + case XKB_KEY_Super_R: + case XKB_KEY_Hyper_L: + case XKB_KEY_Hyper_R: + return TRUE; + default: + return FALSE; } - - return retval; } static void -invoke_handler (MetaDisplay *display, - MetaScreen *screen, - MetaKeyHandler *handler, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding) - +invoke_handler (MetaDisplay *display, + MetaScreen *screen, + MetaKeyHandler *handler, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding) { if (handler->func) (* handler->func) (display, screen, @@ -1666,33 +1648,26 @@ static gboolean process_event (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, - XIDeviceEvent *event, - gboolean on_window) + ClutterKeyEvent *event) { MetaKeyBinding *binding; /* we used to have release-based bindings but no longer. */ - if (event->evtype == XI_KeyRelease) + if (event->type == CLUTTER_KEY_RELEASE) return FALSE; binding = display_get_keybinding (display, - event->detail, - event->mods.effective); + event->hardware_keycode, + event->modifier_state); if (!binding || - (!on_window && binding->flags & META_KEY_BINDING_PER_WINDOW) || - meta_compositor_filter_keybinding (display->compositor, screen, binding)) + (!window && binding->flags & META_KEY_BINDING_PER_WINDOW)) goto not_found; - /* - * window must be non-NULL for on_window to be true, - * and so also window must be non-NULL if we get here and - * this is a META_KEY_BINDING_PER_WINDOW binding. - */ - - meta_topic (META_DEBUG_KEYBINDINGS, - "Binding keycode 0x%x mask 0x%x matches event 0x%x state 0x%x\n", - binding->keycode, binding->mask, - event->detail, event->mods.effective); + /* If the compositor filtered out the keybindings, that + * means they don't want the binding to trigger, so we do + * the same thing as if the binding didn't exist. */ + if (meta_compositor_filter_keybinding (display->compositor, binding)) + goto not_found; if (binding->handler == NULL) meta_bug ("Binding %s has no handler\n", binding->name); @@ -1720,12 +1695,12 @@ process_event (MetaDisplay *display, static gboolean process_overlay_key (MetaDisplay *display, MetaScreen *screen, - XIDeviceEvent *event, - KeySym keysym) + ClutterKeyEvent *event, + MetaWindow *window) { if (display->overlay_key_only_pressed) { - if (event->detail != (int)display->overlay_key_combo.keycode) + if (event->hardware_keycode != (int)display->overlay_key_combo.keycode) { display->overlay_key_only_pressed = FALSE; @@ -1741,38 +1716,42 @@ process_overlay_key (MetaDisplay *display, * the event. Other clients with global grabs will be out of * luck. */ - if (process_event (display, screen, NULL, event, FALSE)) + if (process_event (display, screen, window, event)) { /* As normally, after we've handled a global key * binding, we unfreeze the keyboard but keep the grab * (this is important for something like cycling * windows */ - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIAsyncDevice, event->time); } else { /* Replay the event so it gets delivered to our * per-window key bindings or to the application */ - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIReplayDevice, event->time); } } - else if (event->evtype == XI_KeyRelease) + else if (event->type == CLUTTER_KEY_RELEASE) { MetaKeyBinding *binding; display->overlay_key_only_pressed = FALSE; + /* We want to unfreeze events, but keep the grab so that if the user * starts typing into the overlay we get all the keys */ - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIAsyncDevice, event->time); binding = display_get_keybinding (display, display->overlay_key_combo.keycode, - display->grab_mask); + 0); if (binding && - meta_compositor_filter_keybinding (display->compositor, screen, binding)) + meta_compositor_filter_keybinding (display->compositor, binding)) return TRUE; meta_display_overlay_key_activate (display); } @@ -1790,19 +1769,21 @@ process_overlay_key (MetaDisplay *display, * * https://bugzilla.gnome.org/show_bug.cgi?id=666101 */ - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIAsyncDevice, event->time); } return TRUE; } - else if (event->evtype == XI_KeyPress && - event->detail == (int)display->overlay_key_combo.keycode) + else if (event->type == CLUTTER_KEY_PRESS && + event->hardware_keycode == (int)display->overlay_key_combo.keycode) { display->overlay_key_only_pressed = TRUE; /* We keep the keyboard frozen - this allows us to use ReplayKeyboard * on the next event if it's not the release of the overlay key */ - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XISyncDevice, event->time); return TRUE; @@ -1814,29 +1795,27 @@ process_overlay_key (MetaDisplay *display, static gboolean process_iso_next_group (MetaDisplay *display, MetaScreen *screen, - XIDeviceEvent *event, - KeySym keysym) + ClutterKeyEvent *event) { gboolean activate; - unsigned int mods; int i; - if (event->evtype != XI_KeyPress) + if (event->type == CLUTTER_KEY_RELEASE) return FALSE; activate = FALSE; - mods = (event->mods.effective & 0xff & ~(display->ignored_modifier_mask)); for (i = 0; i < display->n_iso_next_group_combos; ++i) { - if (event->detail == (int)display->iso_next_group_combos[i].keycode && - mods == display->iso_next_group_combos[i].modifiers) + if (event->hardware_keycode == display->iso_next_group_combos[i].keycode && + event->modifier_state == (unsigned int)display->iso_next_group_combos[i].modifiers) { /* If the signal handler returns TRUE the keyboard will remain frozen. It's the signal handler's responsibility to unfreeze it. */ if (!meta_display_modifiers_accelerator_activate (display)) - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIAsyncDevice, event->time); activate = TRUE; break; @@ -1861,57 +1840,33 @@ process_iso_next_group (MetaDisplay *display, * (and help us solve the other fixmes). */ gboolean -meta_display_process_key_event (MetaDisplay *display, - MetaWindow *window, - XIDeviceEvent *event) +meta_display_process_key_event (MetaDisplay *display, + MetaWindow *window, + ClutterKeyEvent *event) { - KeySym keysym; gboolean keep_grab; gboolean all_keys_grabbed; gboolean handled; - const char *str; MetaScreen *screen; - /* if key event was on root window, we have a shortcut */ - screen = meta_display_screen_for_root (display, event->event); - - /* else round-trip to server */ - if (screen == NULL) - screen = meta_display_screen_for_xwindow (display, event->event); - - if (screen == NULL) - return FALSE; /* event window is destroyed */ - - /* ignore key events on popup menus and such. */ - if (meta_ui_window_is_widget (screen->ui, event->event)) - return FALSE; - /* window may be NULL */ - keysym = XKeycodeToKeysym (display->xdisplay, event->detail, 0); - - str = XKeysymToString (keysym); - - /* was topic */ - meta_topic (META_DEBUG_KEYBINDINGS, - "Processing key %s event, keysym: %s state: 0x%x window: %s\n", - event->evtype == XI_KeyPress ? "press" : "release", - str ? str : "none", event->mods.effective, - window ? window->desc : "(no window)"); + screen = display->screen; all_keys_grabbed = window ? window->all_keys_grabbed : screen->all_keys_grabbed; if (!all_keys_grabbed) { - handled = process_overlay_key (display, screen, event, keysym); + handled = process_overlay_key (display, screen, event, window); if (handled) return TRUE; - handled = process_iso_next_group (display, screen, event, keysym); + handled = process_iso_next_group (display, screen, event); if (handled) return TRUE; } - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIAsyncDevice, event->time); keep_grab = TRUE; @@ -1923,8 +1878,7 @@ meta_display_process_key_event (MetaDisplay *display, * we're in some special keyboard mode such as window move * mode. */ - if (window ? (window == display->grab_window) : - (screen == display->grab_screen)) + if ((window && window == display->grab_window) || !window) { switch (display->grab_op) { @@ -1940,16 +1894,14 @@ meta_display_process_key_event (MetaDisplay *display, meta_topic (META_DEBUG_KEYBINDINGS, "Processing event for mouse-only move/resize\n"); g_assert (window != NULL); - keep_grab = process_mouse_move_resize_grab (display, screen, - window, event, keysym); + keep_grab = process_mouse_move_resize_grab (display, screen, window, event); break; case META_GRAB_OP_KEYBOARD_MOVING: meta_topic (META_DEBUG_KEYBINDINGS, "Processing event for keyboard move\n"); g_assert (window != NULL); - keep_grab = process_keyboard_move_grab (display, screen, - window, event, keysym); + keep_grab = process_keyboard_move_grab (display, screen, window, event); break; case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: @@ -1964,8 +1916,7 @@ meta_display_process_key_event (MetaDisplay *display, meta_topic (META_DEBUG_KEYBINDINGS, "Processing event for keyboard resize\n"); g_assert (window != NULL); - keep_grab = process_keyboard_resize_grab (display, screen, - window, event, keysym); + keep_grab = process_keyboard_resize_grab (display, screen, window, event); break; default: @@ -1973,33 +1924,26 @@ meta_display_process_key_event (MetaDisplay *display, } } if (!keep_grab) - { - meta_topic (META_DEBUG_KEYBINDINGS, - "Ending grab op %u on key event sym %s\n", - display->grab_op, XKeysymToString (keysym)); - meta_display_end_grab_op (display, event->time); - } + meta_display_end_grab_op (display, event->time); return TRUE; } /* Do the normal keybindings */ - return process_event (display, screen, window, event, - !all_keys_grabbed && window); + return process_event (display, screen, window, event); } static gboolean -process_mouse_move_resize_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym) +process_mouse_move_resize_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event) { /* don't care about releases, but eat them, don't end grab */ - if (event->evtype == XI_KeyRelease) + if (event->type == CLUTTER_KEY_RELEASE) return TRUE; - if (keysym == XK_Escape) + if (event->keyval == CLUTTER_KEY_Escape) { /* Hide the tiling preview if necessary */ if (window->tile_mode != META_TILE_NONE) @@ -2034,11 +1978,10 @@ process_mouse_move_resize_grab (MetaDisplay *display, } static gboolean -process_keyboard_move_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym) +process_keyboard_move_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event) { gboolean handled; int x, y; @@ -2048,28 +1991,28 @@ process_keyboard_move_grab (MetaDisplay *display, handled = FALSE; /* don't care about releases, but eat them, don't end grab */ - if (event->evtype == XI_KeyRelease) + if (event->type == CLUTTER_KEY_RELEASE) return TRUE; /* don't end grab on modifier key presses */ - if (is_modifier (display, event->detail)) + if (is_modifier (event->keyval)) return TRUE; meta_window_get_position (window, &x, &y); - smart_snap = (event->mods.effective & ShiftMask) != 0; + smart_snap = (event->modifier_state & CLUTTER_SHIFT_MASK) != 0; #define SMALL_INCREMENT 1 #define NORMAL_INCREMENT 10 if (smart_snap) incr = 1; - else if (event->mods.effective & ControlMask) + else if (event->modifier_state & CLUTTER_CONTROL_MASK) incr = SMALL_INCREMENT; else incr = NORMAL_INCREMENT; - if (keysym == XK_Escape) + if (event->keyval == CLUTTER_KEY_Escape) { /* End move and restore to original state. If the window was a * maximized window that had been "shaken loose" we need to @@ -2092,37 +2035,37 @@ process_keyboard_move_grab (MetaDisplay *display, * Shift + arrow to snap is sort of a hidden feature. This way * people using just arrows shouldn't get too frustrated. */ - switch (keysym) + switch (event->keyval) { - case XK_KP_Home: - case XK_KP_Prior: - case XK_Up: - case XK_KP_Up: + case CLUTTER_KEY_KP_Home: + case CLUTTER_KEY_KP_Prior: + case CLUTTER_KEY_Up: + case CLUTTER_KEY_KP_Up: y -= incr; handled = TRUE; break; - case XK_KP_End: - case XK_KP_Next: - case XK_Down: - case XK_KP_Down: + case CLUTTER_KEY_KP_End: + case CLUTTER_KEY_KP_Next: + case CLUTTER_KEY_Down: + case CLUTTER_KEY_KP_Down: y += incr; handled = TRUE; break; } - switch (keysym) + switch (event->keyval) { - case XK_KP_Home: - case XK_KP_End: - case XK_Left: - case XK_KP_Left: + case CLUTTER_KEY_KP_Home: + case CLUTTER_KEY_KP_End: + case CLUTTER_KEY_Left: + case CLUTTER_KEY_KP_Left: x -= incr; handled = TRUE; break; - case XK_KP_Prior: - case XK_KP_Next: - case XK_Right: - case XK_KP_Right: + case CLUTTER_KEY_KP_Prior: + case CLUTTER_KEY_KP_Next: + case CLUTTER_KEY_Right: + case CLUTTER_KEY_KP_Right: x += incr; handled = TRUE; break; @@ -2154,11 +2097,10 @@ process_keyboard_move_grab (MetaDisplay *display, } static gboolean -process_keyboard_resize_grab_op_change (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym) +process_keyboard_resize_grab_op_change (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event) { gboolean handled; @@ -2166,25 +2108,25 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, switch (display->grab_op) { case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: - switch (keysym) + switch (event->keyval) { - case XK_Up: - case XK_KP_Up: + case CLUTTER_KEY_Up: + case CLUTTER_KEY_KP_Up: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; handled = TRUE; break; - case XK_Down: - case XK_KP_Down: + case CLUTTER_KEY_Down: + case CLUTTER_KEY_KP_Down: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; handled = TRUE; break; - case XK_Left: - case XK_KP_Left: + case CLUTTER_KEY_Left: + case CLUTTER_KEY_KP_Left: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; handled = TRUE; break; - case XK_Right: - case XK_KP_Right: + case CLUTTER_KEY_Right: + case CLUTTER_KEY_KP_Right: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; handled = TRUE; break; @@ -2192,15 +2134,15 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, break; case META_GRAB_OP_KEYBOARD_RESIZING_S: - switch (keysym) + switch (event->keyval) { - case XK_Left: - case XK_KP_Left: + case CLUTTER_KEY_Left: + case CLUTTER_KEY_KP_Left: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; handled = TRUE; break; - case XK_Right: - case XK_KP_Right: + case CLUTTER_KEY_Right: + case CLUTTER_KEY_KP_Right: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; handled = TRUE; break; @@ -2208,15 +2150,15 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, break; case META_GRAB_OP_KEYBOARD_RESIZING_N: - switch (keysym) + switch (event->keyval) { - case XK_Left: - case XK_KP_Left: + case CLUTTER_KEY_Left: + case CLUTTER_KEY_KP_Left: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; handled = TRUE; break; - case XK_Right: - case XK_KP_Right: + case CLUTTER_KEY_Right: + case CLUTTER_KEY_KP_Right: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; handled = TRUE; break; @@ -2224,15 +2166,15 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, break; case META_GRAB_OP_KEYBOARD_RESIZING_W: - switch (keysym) + switch (event->keyval) { - case XK_Up: - case XK_KP_Up: + case CLUTTER_KEY_Up: + case CLUTTER_KEY_KP_Up: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; handled = TRUE; break; - case XK_Down: - case XK_KP_Down: + case CLUTTER_KEY_Down: + case CLUTTER_KEY_KP_Down: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; handled = TRUE; break; @@ -2240,15 +2182,15 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, break; case META_GRAB_OP_KEYBOARD_RESIZING_E: - switch (keysym) + switch (event->keyval) { - case XK_Up: - case XK_KP_Up: + case CLUTTER_KEY_Up: + case CLUTTER_KEY_KP_Up: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; handled = TRUE; break; - case XK_Down: - case XK_KP_Down: + case CLUTTER_KEY_Down: + case CLUTTER_KEY_KP_Down: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; handled = TRUE; break; @@ -2276,11 +2218,10 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, } static gboolean -process_keyboard_resize_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym) +process_keyboard_resize_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event) { gboolean handled; int height_inc; @@ -2292,14 +2233,14 @@ process_keyboard_resize_grab (MetaDisplay *display, handled = FALSE; /* don't care about releases, but eat them, don't end grab */ - if (event->evtype == XI_KeyRelease) + if (event->type == CLUTTER_KEY_RELEASE) return TRUE; /* don't end grab on modifier key presses */ - if (is_modifier (display, event->detail)) + if (is_modifier (event->keyval)) return TRUE; - if (keysym == XK_Escape) + if (event->keyval == CLUTTER_KEY_Escape) { /* End resize and restore to original state. */ meta_window_move_resize (display->grab_window, @@ -2312,8 +2253,7 @@ process_keyboard_resize_grab (MetaDisplay *display, return FALSE; } - if (process_keyboard_resize_grab_op_change (display, screen, window, - event, keysym)) + if (process_keyboard_resize_grab_op_change (display, screen, window, event)) return TRUE; width = window->rect.width; @@ -2321,7 +2261,7 @@ process_keyboard_resize_grab (MetaDisplay *display, gravity = meta_resize_gravity_from_grab_op (display->grab_op); - smart_snap = (event->mods.effective & ShiftMask) != 0; + smart_snap = (event->modifier_state & CLUTTER_SHIFT_MASK) != 0; #define SMALL_INCREMENT 1 #define NORMAL_INCREMENT 10 @@ -2331,7 +2271,7 @@ process_keyboard_resize_grab (MetaDisplay *display, height_inc = 1; width_inc = 1; } - else if (event->mods.effective & ControlMask) + else if (event->modifier_state & CLUTTER_CONTROL_MASK) { width_inc = SMALL_INCREMENT; height_inc = SMALL_INCREMENT; @@ -2350,10 +2290,10 @@ process_keyboard_resize_grab (MetaDisplay *display, if (window->size_hints.height_inc > 1) height_inc = window->size_hints.height_inc; - switch (keysym) + switch (event->keyval) { - case XK_Up: - case XK_KP_Up: + case CLUTTER_KEY_Up: + case CLUTTER_KEY_KP_Up: switch (gravity) { case NorthGravity: @@ -2380,8 +2320,8 @@ process_keyboard_resize_grab (MetaDisplay *display, handled = TRUE; break; - case XK_Down: - case XK_KP_Down: + case CLUTTER_KEY_Down: + case CLUTTER_KEY_KP_Down: switch (gravity) { case NorthGravity: @@ -2408,8 +2348,8 @@ process_keyboard_resize_grab (MetaDisplay *display, handled = TRUE; break; - case XK_Left: - case XK_KP_Left: + case CLUTTER_KEY_Left: + case CLUTTER_KEY_KP_Left: switch (gravity) { case EastGravity: @@ -2436,8 +2376,8 @@ process_keyboard_resize_grab (MetaDisplay *display, handled = TRUE; break; - case XK_Right: - case XK_KP_Right: + case CLUTTER_KEY_Right: + case CLUTTER_KEY_KP_Right: switch (gravity) { case EastGravity: @@ -2512,12 +2452,12 @@ process_keyboard_resize_grab (MetaDisplay *display, } static void -handle_switch_to_workspace (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *event_window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_switch_to_workspace (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *event_window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { gint which = binding->handler->data; MetaWorkspace *workspace; @@ -2536,12 +2476,12 @@ handle_switch_to_workspace (MetaDisplay *display, static void -handle_maximize_vertically (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_maximize_vertically (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_resize_func) { @@ -2553,12 +2493,12 @@ handle_maximize_vertically (MetaDisplay *display, } static void -handle_maximize_horizontally (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_maximize_horizontally (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_resize_func) { @@ -2570,12 +2510,12 @@ handle_maximize_horizontally (MetaDisplay *display, } static void -handle_always_on_top (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_always_on_top (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->wm_state_above == FALSE) meta_window_make_above (window); @@ -2631,100 +2571,100 @@ handle_move_to_corner_backend (MetaDisplay *display, } static void -handle_move_to_corner_nw (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_corner_nw (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, FALSE, FALSE, dummy); } static void -handle_move_to_corner_ne (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_corner_ne (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, TRUE, FALSE, dummy); } static void -handle_move_to_corner_sw (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_corner_sw (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, FALSE, TRUE, dummy); } static void -handle_move_to_corner_se (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_corner_se (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, TRUE, TRUE, dummy); } static void -handle_move_to_side_n (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_side_n (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, FALSE, TRUE, FALSE, FALSE, dummy); } static void -handle_move_to_side_s (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_side_s (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, FALSE, TRUE, FALSE, TRUE, dummy); } static void -handle_move_to_side_e (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_side_e (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, FALSE, TRUE, FALSE, dummy); } static void -handle_move_to_side_w (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_side_w (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, FALSE, FALSE, FALSE, dummy); } static void -handle_move_to_center (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_center (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { MetaRectangle work_area; MetaRectangle frame_rect; @@ -2747,12 +2687,12 @@ handle_move_to_center (MetaDisplay *display, } static void -handle_show_desktop (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_show_desktop (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (screen->active_workspace->showing_desktop) { @@ -2766,12 +2706,12 @@ handle_show_desktop (MetaDisplay *display, } static void -handle_panel (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_panel (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { MetaKeyBindingAction action = binding->handler->data; Atom action_atom; @@ -2799,7 +2739,7 @@ handle_panel (MetaDisplay *display, ev.data.l[1] = event->time; meta_topic (META_DEBUG_KEYBINDINGS, - "Sending panel message with timestamp %lu, and turning mouse_mode " + "Sending panel message with timestamp %u, and turning mouse_mode " "off due to keybinding press\n", event->time); display->mouse_mode = FALSE; @@ -2818,12 +2758,12 @@ handle_panel (MetaDisplay *display, } static void -handle_activate_window_menu (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *event_window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_activate_window_menu (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *event_window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (display->focus_window) { @@ -2843,12 +2783,12 @@ handle_activate_window_menu (MetaDisplay *display, } static void -do_choose_window (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *event_window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gboolean backward) +do_choose_window (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *event_window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gboolean backward) { MetaTabList type = binding->handler->data; MetaWindow *initial_selection; @@ -2857,12 +2797,11 @@ do_choose_window (MetaDisplay *display, "Tab list = %u\n", type); /* reverse direction if shift is down */ - if (event->mods.effective & ShiftMask) + if (event->modifier_state & CLUTTER_SHIFT_MASK) backward = !backward; initial_selection = meta_display_get_tab_next (display, type, - screen, screen->active_workspace, NULL, backward); @@ -2871,36 +2810,36 @@ do_choose_window (MetaDisplay *display, } static void -handle_switch (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *event_window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_switch (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *event_window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { gint backwards = (binding->handler->flags & META_KEY_BINDING_IS_REVERSED) != 0; do_choose_window (display, screen, event_window, event, binding, backwards); } static void -handle_cycle (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *event_window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_cycle (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *event_window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { gint backwards = (binding->handler->flags & META_KEY_BINDING_IS_REVERSED) != 0; do_choose_window (display, screen, event_window, event, binding, backwards); } static void -handle_toggle_fullscreen (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_fullscreen (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->fullscreen) meta_window_unmake_fullscreen (window); @@ -2909,12 +2848,12 @@ handle_toggle_fullscreen (MetaDisplay *display, } static void -handle_toggle_above (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_above (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->wm_state_above) meta_window_unmake_above (window); @@ -2923,12 +2862,12 @@ handle_toggle_above (MetaDisplay *display, } static void -handle_toggle_tiled (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_tiled (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { MetaTileMode mode = binding->handler->data; @@ -2961,12 +2900,12 @@ handle_toggle_tiled (MetaDisplay *display, } static void -handle_toggle_maximized (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_maximized (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (META_WINDOW_MAXIMIZED (window)) meta_window_unmaximize (window, META_MAXIMIZE_BOTH); @@ -2975,36 +2914,36 @@ handle_toggle_maximized (MetaDisplay *display, } static void -handle_maximize (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_maximize (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_maximize_func) meta_window_maximize (window, META_MAXIMIZE_BOTH); } static void -handle_unmaximize (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_unmaximize (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->maximized_vertically || window->maximized_horizontally) meta_window_unmaximize (window, META_MAXIMIZE_BOTH); } static void -handle_toggle_shaded (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_shaded (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->shaded) meta_window_unshade (window, event->time); @@ -3013,36 +2952,36 @@ handle_toggle_shaded (MetaDisplay *display, } static void -handle_close (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_close (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_close_func) meta_window_delete (window, event->time); } static void -handle_minimize (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_minimize (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_minimize_func) meta_window_minimize (window); } static void -handle_begin_move (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_begin_move (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_move_func) { @@ -3054,12 +2993,12 @@ handle_begin_move (MetaDisplay *display, } static void -handle_begin_resize (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_begin_resize (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_resize_func) { @@ -3071,12 +3010,12 @@ handle_begin_resize (MetaDisplay *display, } static void -handle_toggle_on_all_workspaces (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_on_all_workspaces (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->on_all_workspaces_requested) meta_window_unstick (window); @@ -3085,12 +3024,12 @@ handle_toggle_on_all_workspaces (MetaDisplay *display, } static void -handle_move_to_workspace (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_workspace (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { gint which = binding->handler->data; gboolean flip = (which < 0); @@ -3143,7 +3082,7 @@ static void handle_move_to_monitor (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, - XIDeviceEvent *event, + ClutterKeyEvent *event, MetaKeyBinding *binding, gpointer dummy) { @@ -3160,12 +3099,12 @@ handle_move_to_monitor (MetaDisplay *display, } static void -handle_raise_or_lower (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_raise_or_lower (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { /* Get window at pointer */ @@ -3207,38 +3146,56 @@ handle_raise_or_lower (MetaDisplay *display, } static void -handle_raise (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_raise (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { meta_window_raise (window); } static void -handle_lower (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_lower (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { meta_window_lower (window); } static void -handle_set_spew_mark (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_set_spew_mark (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { meta_verbose ("-- MARK MARK MARK MARK --\n"); } +static void +handle_switch_vt (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) +{ + gint vt = binding->handler->data; + GError *error = NULL; + + if (!meta_activate_vt (vt, &error)) + { + g_warning ("Failed to switch VT: %s", error->message); + g_error_free (error); + } +} + /** * meta_keybindings_set_custom_handler: * @name: The name of the keybinding to set @@ -3280,6 +3237,7 @@ init_builtin_key_bindings (MetaDisplay *display) META_KEY_BINDING_IS_REVERSED) GSettings *common_keybindings = g_settings_new (SCHEMA_COMMON_KEYBINDINGS); GSettings *mutter_keybindings = g_settings_new (SCHEMA_MUTTER_KEYBINDINGS); + GSettings *mutter_wayland_keybindings = g_settings_new (SCHEMA_MUTTER_WAYLAND_KEYBINDINGS); add_builtin_keybinding (display, "switch-to-workspace-1", @@ -3521,6 +3479,58 @@ init_builtin_key_bindings (MetaDisplay *display) META_KEYBINDING_ACTION_SET_SPEW_MARK, handle_set_spew_mark, 0); + if (meta_is_wayland_compositor ()) + { + add_builtin_keybinding (display, + "switch-to-session-1", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 1); + + add_builtin_keybinding (display, + "switch-to-session-2", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 2); + + add_builtin_keybinding (display, + "switch-to-session-3", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 3); + + add_builtin_keybinding (display, + "switch-to-session-4", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 4); + + add_builtin_keybinding (display, + "switch-to-session-5", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 5); + + add_builtin_keybinding (display, + "switch-to-session-6", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 6); + + add_builtin_keybinding (display, + "switch-to-session-7", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 7); + } + #undef REVERSES_AND_REVERSED /************************ PER WINDOW BINDINGS ************************/ @@ -3874,6 +3884,7 @@ init_builtin_key_bindings (MetaDisplay *display) g_object_unref (common_keybindings); g_object_unref (mutter_keybindings); + g_object_unref (mutter_wayland_keybindings); } void @@ -3884,12 +3895,9 @@ meta_display_init_keys (MetaDisplay *display) /* Keybindings */ display->keymap = NULL; display->keysyms_per_keycode = 0; - display->modmap = NULL; display->min_keycode = 0; display->max_keycode = 0; display->ignored_modifier_mask = 0; - display->num_lock_mask = 0; - display->scroll_lock_mask = 0; display->hyper_mask = 0; display->super_mask = 0; display->meta_mask = 0; diff --git a/src/core/main.c b/src/core/main.c index 3f5f3c5..a3d000e 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -50,12 +50,11 @@ #include "display-private.h" #include <meta/errors.h> #include "ui.h" -#include "session.h" #include <meta/prefs.h> #include <meta/compositor.h> #include <glib-object.h> -#include <gdk/gdkx.h> +#include <glib-unix.h> #include <stdlib.h> #include <sys/types.h> @@ -71,12 +70,16 @@ #include <unistd.h> #include <clutter/clutter.h> -#include <clutter/x11/clutter-x11.h> #ifdef HAVE_INTROSPECTION #include <girepository.h> #endif +#include "x11/session.h" + +#include "wayland/meta-wayland.h" +#include "backends/meta-backend.h" + /* * The exit code we'll return to our parent process when we eventually die. */ @@ -187,6 +190,8 @@ static gchar *opt_client_id; static gboolean opt_replace_wm; static gboolean opt_disable_sm; static gboolean opt_sync; +static gboolean opt_wayland; +static gboolean opt_display_server; static GOptionEntry meta_options[] = { { @@ -224,6 +229,17 @@ static GOptionEntry meta_options[] = { N_("Make X calls synchronous"), NULL }, + { + "wayland", 0, 0, G_OPTION_ARG_NONE, + &opt_wayland, + N_("Run as a wayland compositor"), + NULL + }, + { + "display-server", 0, 0, G_OPTION_ARG_NONE, + &opt_display_server, + N_("Run as a full display server, rather than nested") + }, {NULL} }; @@ -247,78 +263,9 @@ meta_get_option_context (void) ctx = g_option_context_new (NULL); g_option_context_add_main_entries (ctx, meta_options, GETTEXT_PACKAGE); - g_option_context_add_group (ctx, clutter_get_option_group_without_init ()); - g_option_context_add_group (ctx, cogl_get_option_group ()); - return ctx; } -/* Mutter is responsible for pulling events off the X queue, so Clutter - * doesn't need (and shouldn't) run its normal event source which polls - * the X fd, but we do have to deal with dispatching events that accumulate - * in the clutter queue. This happens, for example, when clutter generate - * enter/leave events on mouse motion - several events are queued in the - * clutter queue but only one dispatched. It could also happen because of - * explicit calls to clutter_event_put(). We add a very simple custom - * event loop source which is simply responsible for pulling events off - * of the queue and dispatching them before we block for new events. - */ - -static gboolean -event_prepare (GSource *source, - gint *timeout_) -{ - *timeout_ = -1; - - return clutter_events_pending (); -} - -static gboolean -event_check (GSource *source) -{ - return clutter_events_pending (); -} - -static gboolean -event_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - ClutterEvent *event = clutter_event_get (); - - if (event) - { - clutter_do_event (event); - clutter_event_free (event); - } - - return TRUE; -} - -static GSourceFuncs event_funcs = { - event_prepare, - event_check, - event_dispatch -}; - -static void -meta_clutter_init (void) -{ - clutter_x11_set_display (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); - clutter_x11_disable_event_retrieval (); - - if (CLUTTER_INIT_SUCCESS == clutter_init (NULL, NULL)) - { - GSource *source = g_source_new (&event_funcs, sizeof (GSource)); - g_source_attach (source, NULL); - g_source_unref (source); - } - else - { - meta_fatal ("Unable to initialize Clutter.\n"); - } -} - /** * meta_select_display: * @@ -328,16 +275,17 @@ meta_clutter_init (void) * also is %NULL, use the default - :0.0 */ static void -meta_select_display (gchar *display_name) +meta_select_display (char *display_arg) { - gchar *envVar = ""; + const char *display_name; + + if (display_arg) + display_name = (const char *) display_arg; + else + display_name = g_getenv ("MUTTER_DISPLAY"); + if (display_name) - envVar = g_strconcat ("DISPLAY=", display_name, NULL); - else if (g_getenv ("MUTTER_DISPLAY")) - envVar = g_strconcat ("DISPLAY=", - g_getenv ("MUTTER_DISPLAY"), NULL); - /* DO NOT FREE envVar, putenv() sucks */ - putenv (envVar); + g_setenv ("DISPLAY", display_name, TRUE); } static void @@ -348,28 +296,17 @@ meta_finalize (void) if (display) meta_display_close (display, CurrentTime); /* I doubt correct timestamps matter here */ -} - -static int sigterm_pipe_fds[2] = { -1, -1 }; -static void -sigterm_handler (int signum) -{ - if (sigterm_pipe_fds[1] >= 0) - { - int G_GNUC_UNUSED dummy; - - dummy = write (sigterm_pipe_fds[1], "", 1); - close (sigterm_pipe_fds[1]); - sigterm_pipe_fds[1] = -1; - } + if (meta_is_wayland_compositor ()) + meta_wayland_finalize (); } static gboolean -on_sigterm (void) +on_sigterm (gpointer user_data) { - meta_quit (META_EXIT_SUCCESS); - return FALSE; + meta_quit (EXIT_SUCCESS); + + return G_SOURCE_REMOVE; } /** @@ -383,9 +320,8 @@ meta_init (void) { struct sigaction act; sigset_t empty_mask; - GIOChannel *channel; ClutterSettings *clutter_settings; - + sigemptyset (&empty_mask); act.sa_handler = SIG_IGN; act.sa_mask = empty_mask; @@ -399,26 +335,18 @@ meta_init (void) g_strerror (errno)); #endif - if (pipe (sigterm_pipe_fds) != 0) - g_printerr ("Failed to create SIGTERM pipe: %s\n", - g_strerror (errno)); - - channel = g_io_channel_unix_new (sigterm_pipe_fds[0]); - g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); - g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_sigterm, NULL); - g_io_channel_set_close_on_unref (channel, TRUE); - g_io_channel_unref (channel); - - act.sa_handler = &sigterm_handler; - if (sigaction (SIGTERM, &act, NULL) < 0) - g_printerr ("Failed to register SIGTERM handler: %s\n", - g_strerror (errno)); + g_unix_signal_add (SIGTERM, on_sigterm, NULL); if (g_getenv ("MUTTER_VERBOSE")) meta_set_verbose (TRUE); if (g_getenv ("MUTTER_DEBUG")) meta_set_debugging (TRUE); + if (opt_display_server) + clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL); + + meta_set_is_wayland_compositor (opt_wayland); + if (g_get_home_dir ()) if (chdir (g_get_home_dir ()) < 0) meta_warning ("Could not change to home directory %s.\n", @@ -430,9 +358,16 @@ meta_init (void) g_irepository_prepend_search_path (MUTTER_PKGLIBDIR); #endif - meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL)); + if (meta_is_wayland_compositor ()) + { + /* NB: When running as a hybrid wayland compositor we run our own headless X + * server so the user can't control the X display to connect too. */ + meta_wayland_init (); + } + else + meta_select_display (opt_display_name); - meta_select_display (opt_display_name); + meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL)); if (opt_replace_wm) meta_set_replace_current_wm (TRUE); @@ -441,13 +376,20 @@ meta_init (void) meta_fatal ("Can't specify both SM save file and SM client id\n"); meta_main_loop = g_main_loop_new (NULL, FALSE); - + meta_ui_init (); - /* - * Clutter can only be initialized after the UI. - */ - meta_clutter_init (); + /* If we are running with wayland then we don't wait until we have + * an X connection before initializing clutter we instead initialize + * it earlier since we need to initialize the GL driver so the driver + * can register any needed wayland extensions. */ + if (!meta_is_wayland_compositor ()) + { + /* + * Clutter can only be initialized after the UI. + */ + meta_clutter_init (); + } /* * XXX: We cannot handle high dpi scaling yet, so fix the scale to 1 diff --git a/src/core/meta-accel-parse.c b/src/core/meta-accel-parse.c new file mode 100644 index 0000000..e9d3054 --- /dev/null +++ b/src/core/meta-accel-parse.c @@ -0,0 +1,355 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#include "config.h" + +#include "meta-accel-parse.h" + +#include <xkbcommon/xkbcommon.h> +#include <string.h> +#include <stdlib.h> + +/* This is copied from GTK+ and modified to work with mutter's + * internal structures. Originating code comes from gtk/gtkaccelgroup.c + */ + +static inline gboolean +is_alt (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'a' || string[1] == 'A') && + (string[2] == 'l' || string[2] == 'L') && + (string[3] == 't' || string[3] == 'T') && + (string[4] == '>')); +} + +static inline gboolean +is_ctl (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 't' || string[2] == 'T') && + (string[3] == 'l' || string[3] == 'L') && + (string[4] == '>')); +} + +static inline gboolean +is_modx (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'm' || string[1] == 'M') && + (string[2] == 'o' || string[2] == 'O') && + (string[3] == 'd' || string[3] == 'D') && + (string[4] >= '1' && string[4] <= '5') && + (string[5] == '>')); +} + +static inline gboolean +is_ctrl (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 't' || string[2] == 'T') && + (string[3] == 'r' || string[3] == 'R') && + (string[4] == 'l' || string[4] == 'L') && + (string[5] == '>')); +} + +static inline gboolean +is_shft (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'h' || string[2] == 'H') && + (string[3] == 'f' || string[3] == 'F') && + (string[4] == 't' || string[4] == 'T') && + (string[5] == '>')); +} + +static inline gboolean +is_shift (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'h' || string[2] == 'H') && + (string[3] == 'i' || string[3] == 'I') && + (string[4] == 'f' || string[4] == 'F') && + (string[5] == 't' || string[5] == 'T') && + (string[6] == '>')); +} + +static inline gboolean +is_control (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 'o' || string[2] == 'O') && + (string[3] == 'n' || string[3] == 'N') && + (string[4] == 't' || string[4] == 'T') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == 'o' || string[6] == 'O') && + (string[7] == 'l' || string[7] == 'L') && + (string[8] == '>')); +} + +static inline gboolean +is_meta (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'm' || string[1] == 'M') && + (string[2] == 'e' || string[2] == 'E') && + (string[3] == 't' || string[3] == 'T') && + (string[4] == 'a' || string[4] == 'A') && + (string[5] == '>')); +} + +static inline gboolean +is_super (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'u' || string[2] == 'U') && + (string[3] == 'p' || string[3] == 'P') && + (string[4] == 'e' || string[4] == 'E') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == '>')); +} + +static inline gboolean +is_hyper (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'h' || string[1] == 'H') && + (string[2] == 'y' || string[2] == 'Y') && + (string[3] == 'p' || string[3] == 'P') && + (string[4] == 'e' || string[4] == 'E') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == '>')); +} + +static inline gboolean +is_primary (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'p' || string[1] == 'P') && + (string[2] == 'r' || string[2] == 'R') && + (string[3] == 'i' || string[3] == 'I') && + (string[4] == 'm' || string[4] == 'M') && + (string[5] == 'a' || string[5] == 'A') && + (string[6] == 'r' || string[6] == 'R') && + (string[7] == 'y' || string[7] == 'Y') && + (string[8] == '>')); +} + +static inline gboolean +is_keycode (const gchar *string) +{ + return (string[0] == '0' && + string[1] == 'x' && + g_ascii_isxdigit (string[2]) && + g_ascii_isxdigit (string[3])); +} + +static gboolean +accelerator_parse (const gchar *accelerator, + guint *accelerator_key, + guint *accelerator_keycode, + MetaVirtualModifier *accelerator_mods) +{ + gboolean error = FALSE; + guint keyval, keycode; + MetaVirtualModifier mods; + gint len; + + if (accelerator_key) + *accelerator_key = 0; + if (accelerator_keycode) + *accelerator_keycode = 0; + if (accelerator_mods) + *accelerator_mods = 0; + + if (accelerator == NULL) + { + error = TRUE; + goto out; + } + + keyval = 0; + mods = 0; + len = strlen (accelerator); + while (len) + { + if (*accelerator == '<') + { + if (len >= 9 && is_primary (accelerator)) + { + /* Primary is treated the same as Control */ + accelerator += 9; + len -= 9; + mods |= META_VIRTUAL_CONTROL_MASK; + } + else if (len >= 9 && is_control (accelerator)) + { + accelerator += 9; + len -= 9; + mods |= META_VIRTUAL_CONTROL_MASK; + } + else if (len >= 7 && is_shift (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= META_VIRTUAL_SHIFT_MASK; + } + else if (len >= 6 && is_shft (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= META_VIRTUAL_SHIFT_MASK; + } + else if (len >= 6 && is_ctrl (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= META_VIRTUAL_CONTROL_MASK; + } + else if (len >= 6 && is_modx (accelerator)) + { + static const guint mod_vals[] = { + META_VIRTUAL_ALT_MASK, + META_VIRTUAL_MOD2_MASK, + META_VIRTUAL_MOD3_MASK, + META_VIRTUAL_MOD4_MASK, + META_VIRTUAL_MOD5_MASK, + }; + + len -= 6; + accelerator += 4; + mods |= mod_vals[*accelerator - '1']; + accelerator += 2; + } + else if (len >= 5 && is_ctl (accelerator)) + { + accelerator += 5; + len -= 5; + mods |= META_VIRTUAL_CONTROL_MASK; + } + else if (len >= 5 && is_alt (accelerator)) + { + accelerator += 5; + len -= 5; + mods |= META_VIRTUAL_ALT_MASK; + } + else if (len >= 6 && is_meta (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= META_VIRTUAL_META_MASK; + } + else if (len >= 7 && is_hyper (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= META_VIRTUAL_HYPER_MASK; + } + else if (len >= 7 && is_super (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= META_VIRTUAL_SUPER_MASK; + } + else + { + gchar last_ch; + + last_ch = *accelerator; + while (last_ch && last_ch != '>') + { + last_ch = *accelerator; + accelerator += 1; + len -= 1; + } + } + } + else + { + if (len >= 4 && is_keycode (accelerator)) + { + keycode = strtoul (accelerator, NULL, 16); + goto out; + } + else if (strcmp (accelerator, "Above_Tab") == 0) + { + keyval = META_KEY_ABOVE_TAB; + goto out; + } + else + { + keyval = xkb_keysym_from_name (accelerator, XKB_KEYSYM_CASE_INSENSITIVE); + if (keyval == XKB_KEY_NoSymbol) + { + error = TRUE; + goto out; + } + } + + accelerator += len; + len -= len; + } + } + +out: + if (error) + return FALSE; + + if (accelerator_key) + *accelerator_key = keyval; + if (accelerator_keycode) + *accelerator_keycode = keycode; + if (accelerator_mods) + *accelerator_mods = mods; + + return TRUE; +} + +gboolean +meta_parse_accelerator (const char *accel, + unsigned int *keysym, + unsigned int *keycode, + MetaVirtualModifier *mask) +{ + if (!accel[0] || strcmp (accel, "disabled") == 0) + return TRUE; + + return accelerator_parse (accel, keysym, keycode, mask); +} + +gboolean +meta_parse_modifier (const char *accel, + MetaVirtualModifier *mask) +{ + if (accel == NULL || !accel[0] || strcmp (accel, "disabled") == 0) + return TRUE; + + return accelerator_parse (accel, NULL, NULL, mask); +} diff --git a/src/core/meta-accel-parse.h b/src/core/meta-accel-parse.h new file mode 100644 index 0000000..1d58375 --- /dev/null +++ b/src/core/meta-accel-parse.h @@ -0,0 +1,43 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2014 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#ifndef META_ACCEL_PARSE_H +#define META_ACCEL_PARSE_H + +#include <glib.h> +#include <meta/common.h> + +/* Not a real key symbol but means "key above the tab key"; this is + * used as the default keybinding for cycle_group. + * 0x2xxxxxxx is a range not used by GDK or X. the remaining digits are + * randomly chosen */ +#define META_KEY_ABOVE_TAB 0x2f7259c9 + +gboolean meta_parse_accelerator (const char *accel, + unsigned int *keysym, + unsigned int *keycode, + MetaVirtualModifier *mask); +gboolean meta_parse_modifier (const char *accel, + MetaVirtualModifier *mask); + +#endif /* META_ACCEL_PARSE_H */ diff --git a/src/core/meta-cursor-tracker.c b/src/core/meta-cursor-tracker.c deleted file mode 100644 index bf6bd69..0000000 --- a/src/core/meta-cursor-tracker.c +++ /dev/null @@ -1,412 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright 2013 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - * Author: Giovanni Campagna <gcampagn@redhat.com> - */ - -/** - * SECTION:cursor-tracker - * @title: MetaCursorTracker - * @short_description: Mutter cursor tracking helper - */ - -#include <config.h> -#include <meta/main.h> -#include <meta/util.h> -#include <meta/errors.h> - -#include <cogl/cogl.h> -#include <clutter/clutter.h> - -#include <gdk/gdk.h> -#include <gdk/gdkx.h> - -#include <X11/cursorfont.h> -#include <X11/extensions/Xfixes.h> -#include <X11/Xcursor/Xcursor.h> - -#include "meta-cursor-tracker-private.h" -#include "screen-private.h" - -#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7 -#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4 - -struct _MetaCursorTracker { - GObject parent_instance; - - MetaScreen *screen; - - gboolean is_showing; - - CoglTexture2D *sprite; - int hot_x, hot_y; -}; - -struct _MetaCursorTrackerClass { - GObjectClass parent_class; -}; - -G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT); - -enum { - CURSOR_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -static void -translate_meta_cursor (MetaCursor cursor, - guint *glyph_out, - const char **name_out) -{ - guint glyph = XC_num_glyphs; - const char *name = NULL; - - switch (cursor) - { - case META_CURSOR_DEFAULT: - glyph = XC_left_ptr; - break; - case META_CURSOR_NORTH_RESIZE: - glyph = XC_top_side; - break; - case META_CURSOR_SOUTH_RESIZE: - glyph = XC_bottom_side; - break; - case META_CURSOR_WEST_RESIZE: - glyph = XC_left_side; - break; - case META_CURSOR_EAST_RESIZE: - glyph = XC_right_side; - break; - case META_CURSOR_SE_RESIZE: - glyph = XC_bottom_right_corner; - break; - case META_CURSOR_SW_RESIZE: - glyph = XC_bottom_left_corner; - break; - case META_CURSOR_NE_RESIZE: - glyph = XC_top_right_corner; - break; - case META_CURSOR_NW_RESIZE: - glyph = XC_top_left_corner; - break; - case META_CURSOR_MOVE_OR_RESIZE_WINDOW: - glyph = XC_fleur; - break; - case META_CURSOR_BUSY: - glyph = XC_watch; - break; - case META_CURSOR_DND_IN_DRAG: - name = "dnd-none"; - break; - case META_CURSOR_DND_MOVE: - name = "dnd-move"; - break; - case META_CURSOR_DND_COPY: - name = "dnd-copy"; - break; - case META_CURSOR_DND_UNSUPPORTED_TARGET: - name = "dnd-none"; - break; - case META_CURSOR_POINTING_HAND: - glyph = XC_hand2; - break; - case META_CURSOR_CROSSHAIR: - glyph = XC_crosshair; - break; - case META_CURSOR_IBEAM: - glyph = XC_xterm; - break; - - default: - g_assert_not_reached (); - glyph = 0; /* silence compiler */ - break; - } - - *glyph_out = glyph; - *name_out = name; -} - -static Cursor -load_cursor_on_server (MetaDisplay *display, - MetaCursor cursor) -{ - Cursor xcursor; - guint glyph; - const char *name; - - translate_meta_cursor (cursor, &glyph, &name); - - if (name != NULL) - xcursor = XcursorLibraryLoadCursor (display->xdisplay, name); - else - xcursor = XCreateFontCursor (display->xdisplay, glyph); - - return xcursor; -} - -Cursor -meta_display_create_x_cursor (MetaDisplay *display, - MetaCursor cursor) -{ - return load_cursor_on_server (display, cursor); -} - -static void -meta_cursor_tracker_init (MetaCursorTracker *self) -{ - /* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of - * detecting if the system mouse cursor is showing or not. - * - * On wayland we start with the cursor showing - */ - self->is_showing = TRUE; -} - -static void -meta_cursor_tracker_finalize (GObject *object) -{ - MetaCursorTracker *self = META_CURSOR_TRACKER (object); - - if (self->sprite) - cogl_object_unref (self->sprite); - - G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object); -} - -static void -meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = meta_cursor_tracker_finalize; - - signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); -} - -static MetaCursorTracker * -make_x11_cursor_tracker (MetaScreen *screen) -{ - MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL); - self->screen = screen; - - XFixesSelectCursorInput (screen->display->xdisplay, - screen->xroot, - XFixesDisplayCursorNotifyMask); - - return self; -} - -/** - * meta_cursor_tracker_get_for_screen: - * @screen: the #MetaScreen - * - * Retrieves the cursor tracker object for @screen. - * - * Returns: (transfer none): - */ -MetaCursorTracker * -meta_cursor_tracker_get_for_screen (MetaScreen *screen) -{ - MetaCursorTracker *self; - - if (screen->cursor_tracker) - return screen->cursor_tracker; - - self = make_x11_cursor_tracker (screen); - - screen->cursor_tracker = self; - return self; -} - -gboolean -meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, - XEvent *xevent) -{ - XFixesCursorNotifyEvent *notify_event; - - if (xevent->xany.type != tracker->screen->display->xfixes_event_base + XFixesCursorNotify) - return FALSE; - - notify_event = (XFixesCursorNotifyEvent *)xevent; - if (notify_event->subtype != XFixesDisplayCursorNotify) - return FALSE; - - g_clear_pointer (&tracker->sprite, cogl_object_unref); - g_signal_emit (tracker, signals[CURSOR_CHANGED], 0); - - return TRUE; -} - -static void -ensure_xfixes_cursor (MetaCursorTracker *tracker) -{ - XFixesCursorImage *cursor_image; - CoglTexture2D *sprite; - guint8 *cursor_data; - gboolean free_cursor_data; - CoglContext *ctx; - - if (tracker->sprite) - return; - - cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay); - if (!cursor_image) - return; - - /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit - * quantities as arrays of long; we need to convert on 64 bit */ - if (sizeof(long) == 4) - { - cursor_data = (guint8 *)cursor_image->pixels; - free_cursor_data = FALSE; - } - else - { - int i, j; - guint32 *cursor_words; - gulong *p; - guint32 *q; - - cursor_words = g_new (guint32, cursor_image->width * cursor_image->height); - cursor_data = (guint8 *)cursor_words; - - p = cursor_image->pixels; - q = cursor_words; - for (j = 0; j < cursor_image->height; j++) - for (i = 0; i < cursor_image->width; i++) - *(q++) = *(p++); - - free_cursor_data = TRUE; - } - - ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - sprite = cogl_texture_2d_new_from_data (ctx, - cursor_image->width, - cursor_image->height, - CLUTTER_CAIRO_FORMAT_ARGB32, - cursor_image->width * 4, /* stride */ - cursor_data, - NULL); - - if (free_cursor_data) - g_free (cursor_data); - - if (sprite != NULL) - { - tracker->sprite = sprite; - tracker->hot_x = cursor_image->xhot; - tracker->hot_y = cursor_image->yhot; - } - XFree (cursor_image); -} - -/** - * meta_cursor_tracker_get_sprite: - * - * Returns: (transfer none): - */ -CoglTexture * -meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker) -{ - g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL); - - ensure_xfixes_cursor (tracker); - - return COGL_TEXTURE (tracker->sprite); -} - -/** - * meta_cursor_tracker_get_hot: - * @tracker: - * @x: (out): - * @y: (out): - * - */ -void -meta_cursor_tracker_get_hot (MetaCursorTracker *tracker, - int *x, - int *y) -{ - g_return_if_fail (META_IS_CURSOR_TRACKER (tracker)); - - ensure_xfixes_cursor (tracker); - - if (x) - *x = tracker->hot_x; - if (y) - *y = tracker->hot_y; -} - -void -meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, - MetaCursor cursor) -{ - Cursor xcursor; - MetaDisplay *display = tracker->screen->display; - - /* First create a cursor for X11 applications that don't specify their own */ - xcursor = meta_display_create_x_cursor (display, cursor); - - XDefineCursor (display->xdisplay, tracker->screen->xroot, xcursor); - XFlush (display->xdisplay); - XFreeCursor (display->xdisplay, xcursor); -} - -void -meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker, - int *x, - int *y, - ClutterModifierType *mods) -{ - GdkDeviceManager *gmanager; - GdkDevice *gdevice; - GdkScreen *gscreen; - - gmanager = gdk_display_get_device_manager (gdk_display_get_default ()); - gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID); - - gdk_device_get_position (gdevice, &gscreen, x, y); - gdk_device_get_state (gdevice, - gdk_screen_get_root_window (gscreen), - NULL, (GdkModifierType*)mods); -} - -void -meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker, - gboolean visible) -{ - if (visible == tracker->is_showing) - return; - tracker->is_showing = visible; - - if (visible) - XFixesShowCursor (tracker->screen->display->xdisplay, - tracker->screen->xroot); - else - XFixesHideCursor (tracker->screen->display->xdisplay, - tracker->screen->xroot); -} diff --git a/src/core/meta-idle-monitor.c b/src/core/meta-idle-monitor.c deleted file mode 100644 index edc3c61..0000000 --- a/src/core/meta-idle-monitor.c +++ /dev/null @@ -1,889 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright 2013 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and - * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c - */ - -/** - * SECTION:idle-monitor - * @title: MetaIdleMonitor - * @short_description: Mutter idle counter (similar to X's IDLETIME) - */ - -#include "config.h" - -#include <string.h> -#include <clutter/clutter.h> -#include <X11/Xlib.h> -#include <X11/extensions/sync.h> - -#include <meta/util.h> -#include <meta/main.h> -#include <meta/meta-idle-monitor.h> -#include "display-private.h" -#include "meta-idle-monitor-private.h" -#include "meta-dbus-idle-monitor.h" - -G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer)); - -struct _MetaIdleMonitor -{ - GObject parent_instance; - - GHashTable *watches; - GHashTable *alarms; - int device_id; - - /* X11 implementation */ - Display *display; - int sync_event_base; - XSyncCounter counter; - XSyncAlarm user_active_alarm; -}; - -struct _MetaIdleMonitorClass -{ - GObjectClass parent_class; -}; - -typedef struct -{ - MetaIdleMonitor *monitor; - guint id; - MetaIdleMonitorWatchFunc callback; - gpointer user_data; - GDestroyNotify notify; - guint64 timeout_msec; - - /* x11 */ - XSyncAlarm xalarm; - int idle_source_id; -} MetaIdleMonitorWatch; - -enum -{ - PROP_0, - PROP_DEVICE_ID, - PROP_LAST, -}; - -static GParamSpec *obj_props[PROP_LAST]; - -G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT) - -static MetaIdleMonitor *device_monitors[256]; -static int device_id_max; - -static gint64 -_xsyncvalue_to_int64 (XSyncValue value) -{ - return ((guint64) XSyncValueHigh32 (value)) << 32 - | (guint64) XSyncValueLow32 (value); -} - -#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32) - -static void -fire_watch (MetaIdleMonitorWatch *watch) -{ - MetaIdleMonitor *monitor; - guint id; - gboolean is_user_active_watch; - - monitor = watch->monitor; - g_object_ref (monitor); - - if (watch->idle_source_id) - { - g_source_remove (watch->idle_source_id); - watch->idle_source_id = 0; - } - - id = watch->id; - is_user_active_watch = (watch->timeout_msec == 0); - - if (watch->callback) - watch->callback (monitor, id, watch->user_data); - - if (is_user_active_watch) - meta_idle_monitor_remove_watch (monitor, id); - - g_object_unref (monitor); -} - -static XSyncAlarm -_xsync_alarm_set (MetaIdleMonitor *monitor, - XSyncTestType test_type, - guint64 interval, - gboolean want_events) -{ - XSyncAlarmAttributes attr; - XSyncValue delta; - guint flags; - - flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | - XSyncCAValue | XSyncCADelta | XSyncCAEvents; - - XSyncIntToValue (&delta, 0); - attr.trigger.counter = monitor->counter; - attr.trigger.value_type = XSyncAbsolute; - attr.delta = delta; - attr.events = want_events; - - GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value); - attr.trigger.test_type = test_type; - return XSyncCreateAlarm (monitor->display, flags, &attr); -} - -static void -ensure_alarm_rescheduled (Display *dpy, - XSyncAlarm alarm) -{ - XSyncAlarmAttributes attr; - - /* Some versions of Xorg have an issue where alarms aren't - * always rescheduled. Calling XSyncChangeAlarm, even - * without any attributes, will reschedule the alarm. */ - XSyncChangeAlarm (dpy, alarm, 0, &attr); -} - -static void -set_alarm_enabled (Display *dpy, - XSyncAlarm alarm, - gboolean enabled) -{ - XSyncAlarmAttributes attr; - attr.events = enabled; - XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr); -} - -static void -check_x11_watch (gpointer data, - gpointer user_data) -{ - MetaIdleMonitorWatch *watch = data; - XSyncAlarm alarm = (XSyncAlarm) user_data; - - if (watch->xalarm != alarm) - return; - - fire_watch (watch); -} - -static void -meta_idle_monitor_handle_xevent (MetaIdleMonitor *monitor, - XSyncAlarmNotifyEvent *alarm_event) -{ - XSyncAlarm alarm; - GList *watches; - gboolean has_alarm; - - if (alarm_event->state != XSyncAlarmActive) - return; - - alarm = alarm_event->alarm; - - has_alarm = FALSE; - - if (alarm == monitor->user_active_alarm) - { - set_alarm_enabled (monitor->display, - alarm, - FALSE); - has_alarm = TRUE; - } - else if (g_hash_table_contains (monitor->alarms, (gpointer) alarm)) - { - ensure_alarm_rescheduled (monitor->display, - alarm); - has_alarm = TRUE; - } - - if (has_alarm) - { - watches = g_hash_table_get_values (monitor->watches); - - g_list_foreach (watches, check_x11_watch, (gpointer) alarm); - g_list_free (watches); - } -} - -void -meta_idle_monitor_handle_xevent_all (XEvent *xevent) -{ - int i; - - for (i = 0; i <= device_id_max; i++) - if (device_monitors[i]) - meta_idle_monitor_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent); -} - -static char * -counter_name_for_device (int device_id) -{ - if (device_id > 0) - return g_strdup_printf ("DEVICEIDLETIME %d", device_id); - - return g_strdup ("IDLETIME"); -} - -static XSyncCounter -find_idletime_counter (MetaIdleMonitor *monitor) -{ - int i; - int ncounters; - XSyncSystemCounter *counters; - XSyncCounter counter = None; - char *counter_name; - - counter_name = counter_name_for_device (monitor->device_id); - counters = XSyncListSystemCounters (monitor->display, &ncounters); - for (i = 0; i < ncounters; i++) - { - if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0) - { - counter = counters[i].counter; - break; - } - } - XSyncFreeSystemCounterList (counters); - g_free (counter_name); - - return counter; -} - -static guint32 -get_next_watch_serial (void) -{ - static guint32 serial = 0; - g_atomic_int_inc (&serial); - return serial; -} - -static void -idle_monitor_watch_free (MetaIdleMonitorWatch *watch) -{ - MetaIdleMonitor *monitor; - - if (watch == NULL) - return; - - monitor = watch->monitor; - g_object_ref (monitor); - - if (watch->idle_source_id) - { - g_source_remove (watch->idle_source_id); - watch->idle_source_id = 0; - } - - if (watch->notify != NULL) - watch->notify (watch->user_data); - - if (watch->xalarm != monitor->user_active_alarm && - watch->xalarm != None) - { - XSyncDestroyAlarm (monitor->display, watch->xalarm); - g_hash_table_remove (monitor->alarms, (gpointer) watch->xalarm); - } - - g_object_unref (monitor); - g_slice_free (MetaIdleMonitorWatch, watch); -} - -static void -init_xsync (MetaIdleMonitor *monitor) -{ - monitor->counter = find_idletime_counter (monitor); - /* IDLETIME counter not found? */ - if (monitor->counter == None) - { - meta_warning ("IDLETIME counter not found\n"); - return; - } - - monitor->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE); -} - -static void -meta_idle_monitor_dispose (GObject *object) -{ - MetaIdleMonitor *monitor; - - monitor = META_IDLE_MONITOR (object); - - g_clear_pointer (&monitor->watches, g_hash_table_destroy); - g_clear_pointer (&monitor->alarms, g_hash_table_destroy); - - if (monitor->user_active_alarm != None) - { - XSyncDestroyAlarm (monitor->display, monitor->user_active_alarm); - monitor->user_active_alarm = None; - } - - G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object); -} - -static void -meta_idle_monitor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); - - switch (prop_id) - { - case PROP_DEVICE_ID: - g_value_set_int (value, monitor->device_id); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_idle_monitor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); - switch (prop_id) - { - case PROP_DEVICE_ID: - monitor->device_id = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_idle_monitor_constructed (GObject *object) -{ - MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); - - monitor->display = meta_get_display ()->xdisplay; - init_xsync (monitor); -} - -static void -meta_idle_monitor_class_init (MetaIdleMonitorClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = meta_idle_monitor_dispose; - object_class->constructed = meta_idle_monitor_constructed; - object_class->get_property = meta_idle_monitor_get_property; - object_class->set_property = meta_idle_monitor_set_property; - - /** - * MetaIdleMonitor:device_id: - * - * The device to listen to idletime on. - */ - obj_props[PROP_DEVICE_ID] = - g_param_spec_int ("device-id", - "Device ID", - "The device to listen to idletime on", - 0, 255, 0, - G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_DEVICE_ID, obj_props[PROP_DEVICE_ID]); -} - -static void -meta_idle_monitor_init (MetaIdleMonitor *monitor) -{ - monitor->watches = g_hash_table_new_full (NULL, - NULL, - NULL, - (GDestroyNotify)idle_monitor_watch_free); - - monitor->alarms = g_hash_table_new (NULL, NULL); -} - -static void -ensure_device_monitor (int device_id) -{ - if (device_monitors[device_id]) - return; - - device_monitors[device_id] = g_object_new (META_TYPE_IDLE_MONITOR, "device-id", device_id, NULL); - device_id_max = MAX (device_id_max, device_id); -} - -/** - * meta_idle_monitor_get_core: - * - * Returns: (transfer none): the #MetaIdleMonitor that tracks the server-global - * idletime for all devices. To track device-specific idletime, - * use meta_idle_monitor_get_for_device(). - */ -MetaIdleMonitor * -meta_idle_monitor_get_core (void) -{ - ensure_device_monitor (0); - return device_monitors[0]; -} - -/** - * meta_idle_monitor_get_for_device: - * @device_id: the device to get the idle time for. - * - * Returns: (transfer none): a new #MetaIdleMonitor that tracks the - * device-specific idletime for @device. To track server-global idletime - * for all devices, use meta_idle_monitor_get_core(). - */ -MetaIdleMonitor * -meta_idle_monitor_get_for_device (int device_id) -{ - g_return_val_if_fail (device_id > 0 && device_id < 256, NULL); - - ensure_device_monitor (device_id); - return device_monitors[device_id]; -} - -static gboolean -fire_watch_idle (gpointer data) -{ - MetaIdleMonitorWatch *watch = data; - - watch->idle_source_id = 0; - fire_watch (watch); - - return FALSE; -} - -static MetaIdleMonitorWatch * -make_watch (MetaIdleMonitor *monitor, - guint64 timeout_msec, - MetaIdleMonitorWatchFunc callback, - gpointer user_data, - GDestroyNotify notify) -{ - MetaIdleMonitorWatch *watch; - - watch = g_slice_new0 (MetaIdleMonitorWatch); - watch->monitor = monitor; - watch->id = get_next_watch_serial (); - watch->callback = callback; - watch->user_data = user_data; - watch->notify = notify; - watch->timeout_msec = timeout_msec; - - if (timeout_msec != 0) - { - watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE); - - g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm); - - if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec) - watch->idle_source_id = g_idle_add (fire_watch_idle, watch); - } - else if (monitor->user_active_alarm != None) - { - watch->xalarm = monitor->user_active_alarm; - - set_alarm_enabled (monitor->display, monitor->user_active_alarm, TRUE); - } - - g_hash_table_insert (monitor->watches, - GUINT_TO_POINTER (watch->id), - watch); - return watch; -} - -/** - * meta_idle_monitor_add_idle_watch: - * @monitor: A #MetaIdleMonitor - * @interval_msec: The idletime interval, in milliseconds - * @callback: (allow-none): The callback to call when the user has - * accumulated @interval_msec milliseconds of idle time. - * @user_data: (allow-none): The user data to pass to the callback - * @notify: A #GDestroyNotify - * - * Returns: a watch id - * - * Adds a watch for a specific idle time. The callback will be called - * when the user has accumulated @interval_msec milliseconds of idle time. - * This function will return an ID that can either be passed to - * meta_idle_monitor_remove_watch(), or can be used to tell idle time - * watches apart if you have more than one. - * - * Also note that this function will only care about positive transitions - * (user's idle time exceeding a certain time). If you want to know about - * when the user has become active, use - * meta_idle_monitor_add_user_active_watch(). - */ -guint -meta_idle_monitor_add_idle_watch (MetaIdleMonitor *monitor, - guint64 interval_msec, - MetaIdleMonitorWatchFunc callback, - gpointer user_data, - GDestroyNotify notify) -{ - MetaIdleMonitorWatch *watch; - - g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0); - g_return_val_if_fail (interval_msec > 0, 0); - - watch = make_watch (monitor, - interval_msec, - callback, - user_data, - notify); - - return watch->id; -} - -/** - * meta_idle_monitor_add_user_active_watch: - * @monitor: A #MetaIdleMonitor - * @callback: (allow-none): The callback to call when the user is - * active again. - * @user_data: (allow-none): The user data to pass to the callback - * @notify: A #GDestroyNotify - * - * Returns: a watch id - * - * Add a one-time watch to know when the user is active again. - * Note that this watch is one-time and will de-activate after the - * function is called, for efficiency purposes. It's most convenient - * to call this when an idle watch, as added by - * meta_idle_monitor_add_idle_watch(), has triggered. - */ -guint -meta_idle_monitor_add_user_active_watch (MetaIdleMonitor *monitor, - MetaIdleMonitorWatchFunc callback, - gpointer user_data, - GDestroyNotify notify) -{ - MetaIdleMonitorWatch *watch; - - g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0); - - watch = make_watch (monitor, - 0, - callback, - user_data, - notify); - - return watch->id; -} - -/** - * meta_idle_monitor_remove_watch: - * @monitor: A #MetaIdleMonitor - * @id: A watch ID - * - * Removes an idle time watcher, previously added by - * meta_idle_monitor_add_idle_watch() or - * meta_idle_monitor_add_user_active_watch(). - */ -void -meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor, - guint id) -{ - g_return_if_fail (META_IS_IDLE_MONITOR (monitor)); - - g_object_ref (monitor); - g_hash_table_remove (monitor->watches, - GUINT_TO_POINTER (id)); - g_object_unref (monitor); -} - -/** - * meta_idle_monitor_get_idletime: - * @monitor: A #MetaIdleMonitor - * - * Returns: The current idle time, in milliseconds, or -1 for not supported - */ -gint64 -meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor) -{ - XSyncValue value; - - if (!XSyncQueryCounter (monitor->display, monitor->counter, &value)) - return -1; - - return _xsyncvalue_to_int64 (value); -} - -static gboolean -handle_get_idletime (MetaDBusIdleMonitor *skeleton, - GDBusMethodInvocation *invocation, - MetaIdleMonitor *monitor) -{ - guint64 idletime; - - idletime = meta_idle_monitor_get_idletime (monitor); - meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime); - - return TRUE; -} - -typedef struct { - MetaDBusIdleMonitor *dbus_monitor; - MetaIdleMonitor *monitor; - char *dbus_name; - guint watch_id; - guint name_watcher_id; -} DBusWatch; - -static void -destroy_dbus_watch (gpointer data) -{ - DBusWatch *watch = data; - - g_object_unref (watch->dbus_monitor); - g_object_unref (watch->monitor); - g_free (watch->dbus_name); - g_bus_unwatch_name (watch->name_watcher_id); - - g_slice_free (DBusWatch, watch); -} - -static void -dbus_idle_callback (MetaIdleMonitor *monitor, - guint watch_id, - gpointer user_data) -{ - DBusWatch *watch = user_data; - GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor); - - g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton), - watch->dbus_name, - g_dbus_interface_skeleton_get_object_path (skeleton), - "org.gnome.Mutter.IdleMonitor", - "WatchFired", - g_variant_new ("(u)", watch_id), - NULL); -} - -static void -name_vanished_callback (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - DBusWatch *watch = user_data; - - meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id); -} - -static DBusWatch * -make_dbus_watch (MetaDBusIdleMonitor *skeleton, - GDBusMethodInvocation *invocation, - MetaIdleMonitor *monitor) -{ - DBusWatch *watch; - - watch = g_slice_new (DBusWatch); - watch->dbus_monitor = g_object_ref (skeleton); - watch->monitor = g_object_ref (monitor); - watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation)); - watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation), - watch->dbus_name, - G_BUS_NAME_WATCHER_FLAGS_NONE, - NULL, /* appeared */ - name_vanished_callback, - watch, NULL); - - return watch; -} - -static gboolean -handle_add_idle_watch (MetaDBusIdleMonitor *skeleton, - GDBusMethodInvocation *invocation, - guint64 interval, - MetaIdleMonitor *monitor) -{ - DBusWatch *watch; - - watch = make_dbus_watch (skeleton, invocation, monitor); - watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval, - dbus_idle_callback, watch, destroy_dbus_watch); - - meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id); - - return TRUE; -} - -static gboolean -handle_add_user_active_watch (MetaDBusIdleMonitor *skeleton, - GDBusMethodInvocation *invocation, - MetaIdleMonitor *monitor) -{ - DBusWatch *watch; - - watch = make_dbus_watch (skeleton, invocation, monitor); - watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor, - dbus_idle_callback, watch, - destroy_dbus_watch); - - meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id); - - return TRUE; -} - -static gboolean -handle_remove_watch (MetaDBusIdleMonitor *skeleton, - GDBusMethodInvocation *invocation, - guint id, - MetaIdleMonitor *monitor) -{ - meta_idle_monitor_remove_watch (monitor, id); - meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation); - - return TRUE; -} - -static void -create_monitor_skeleton (GDBusObjectManagerServer *manager, - MetaIdleMonitor *monitor, - const char *path) -{ - MetaDBusIdleMonitor *skeleton; - MetaDBusObjectSkeleton *object; - - skeleton = meta_dbus_idle_monitor_skeleton_new (); - g_signal_connect_object (skeleton, "handle-add-idle-watch", - G_CALLBACK (handle_add_idle_watch), monitor, 0); - g_signal_connect_object (skeleton, "handle-add-user-active-watch", - G_CALLBACK (handle_add_user_active_watch), monitor, 0); - g_signal_connect_object (skeleton, "handle-remove-watch", - G_CALLBACK (handle_remove_watch), monitor, 0); - g_signal_connect_object (skeleton, "handle-get-idletime", - G_CALLBACK (handle_get_idletime), monitor, 0); - - object = meta_dbus_object_skeleton_new (path); - meta_dbus_object_skeleton_set_idle_monitor (object, skeleton); - - g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object)); -} - -static void -on_device_added (ClutterDeviceManager *device_manager, - ClutterInputDevice *device, - GDBusObjectManagerServer *manager) -{ - - MetaIdleMonitor *monitor; - int device_id; - char *path; - - device_id = clutter_input_device_get_device_id (device); - monitor = meta_idle_monitor_get_for_device (device_id); - path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id); - - create_monitor_skeleton (manager, monitor, path); - g_free (path); -} - -static void -on_device_removed (ClutterDeviceManager *device_manager, - ClutterInputDevice *device, - GDBusObjectManagerServer *manager) -{ - int device_id; - char *path; - - device_id = clutter_input_device_get_device_id (device); - path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id); - g_dbus_object_manager_server_unexport (manager, path); - g_free (path); - - g_clear_object (&device_monitors[device_id]); - if (device_id == device_id_max) - device_id_max--; -} - -static void -on_bus_acquired (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - GDBusObjectManagerServer *manager; - ClutterDeviceManager *device_manager; - MetaIdleMonitor *monitor; - GSList *devices, *iter; - char *path; - - manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor"); - - /* We never clear the core monitor, as that's supposed to cumulate idle times from - all devices */ - monitor = meta_idle_monitor_get_core (); - path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core"); - create_monitor_skeleton (manager, monitor, path); - g_free (path); - - device_manager = clutter_device_manager_get_default (); - devices = clutter_device_manager_list_devices (device_manager); - - for (iter = devices; iter; iter = iter->next) - on_device_added (device_manager, iter->data, manager); - - g_slist_free (devices); - - g_signal_connect_object (device_manager, "device-added", - G_CALLBACK (on_device_added), manager, 0); - g_signal_connect_object (device_manager, "device-removed", - G_CALLBACK (on_device_removed), manager, 0); - - g_dbus_object_manager_server_set_connection (manager, connection); -} - -static void -on_name_acquired (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - meta_verbose ("Acquired name %s\n", name); -} - -static void -on_name_lost (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - meta_verbose ("Lost or failed to acquire name %s\n", name); -} - -void -meta_idle_monitor_init_dbus (void) -{ - static int dbus_name_id; - - if (dbus_name_id > 0) - return; - - dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION, - "org.gnome.Mutter.IdleMonitor", - G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | - (meta_get_replace_current_wm () ? - G_BUS_NAME_OWNER_FLAGS_REPLACE : 0), - on_bus_acquired, - on_name_acquired, - on_name_lost, - NULL, NULL); -} - diff --git a/src/core/place.c b/src/core/place.c index 8894114..6c0efc1 100644 --- a/src/core/place.c +++ b/src/core/place.c @@ -344,7 +344,7 @@ avoid_being_obscured_as_second_modal_dialog (MetaWindow *window, /* denied_focus_and_not_transient is only set when focus_window != NULL */ if (window->denied_focus_and_not_transient && - window->wm_state_modal && /* FIXME: Maybe do this for all transients? */ + window->type == META_WINDOW_MODAL_DIALOG && meta_window_same_application (window, focus_window) && window_overlaps_focus_window (window)) { @@ -610,7 +610,7 @@ meta_window_place (MetaWindow *window, meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc); windows = NULL; - + switch (window->type) { /* Run placement algorithm on these. */ @@ -638,7 +638,7 @@ meta_window_place (MetaWindow *window, case META_WINDOW_OVERRIDE_OTHER: goto done_no_constraints; } - + if (meta_prefs_get_disable_workarounds ()) { switch (window->type) @@ -699,18 +699,11 @@ meta_window_place (MetaWindow *window, goto done_no_constraints; } } - - if ((window->type == META_WINDOW_DIALOG || - window->type == META_WINDOW_MODAL_DIALOG) && - window->xtransient_for != None) - { - /* Center horizontally, at top of parent vertically */ - MetaWindow *parent; - - parent = - meta_display_lookup_x_window (window->display, - window->xtransient_for); + if (window->type == META_WINDOW_DIALOG || + window->type == META_WINDOW_MODAL_DIALOG) + { + MetaWindow *parent = meta_window_get_transient_for (window); if (parent) { diff --git a/src/core/prefs.c b/src/core/prefs.c index 7720695..98d62ee 100644 --- a/src/core/prefs.c +++ b/src/core/prefs.c @@ -36,6 +36,7 @@ #include <string.h> #include <stdlib.h> #include "keybindings-private.h" +#include "meta-accel-parse.h" /* If you add a key, it needs updating in init() and in the gsettings * notify listener and of course in the .schemas file. @@ -1187,8 +1188,8 @@ maybe_give_disable_workarounds_warning (void) { first_disable = FALSE; - meta_warning (_("Workarounds for broken applications disabled. " - "Some applications may not behave properly.\n")); + meta_warning ("Workarounds for broken applications disabled. " + "Some applications may not behave properly.\n"); } } @@ -1262,8 +1263,8 @@ titlebar_handler (GVariant *value, if (desc == NULL) { - meta_warning (_("Could not parse font description " - "\"%s\" from GSettings key %s\n"), + meta_warning ("Could not parse font description " + "\"%s\" from GSettings key %s\n", string_value ? string_value : "(null)", KEY_TITLEBAR_FONT); return FALSE; @@ -1323,13 +1324,13 @@ mouse_button_mods_handler (GVariant *value, *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); - if (!string_value || !meta_ui_parse_modifier (string_value, &mods)) + if (!string_value || !meta_parse_modifier (string_value, &mods)) { meta_topic (META_DEBUG_KEYBINDINGS, "Failed to parse new GSettings value\n"); - meta_warning (_("\"%s\" found in configuration database is " - "not a valid value for mouse button modifier\n"), + meta_warning ("\"%s\" found in configuration database is " + "not a valid value for mouse button modifier\n", string_value); return FALSE; @@ -1627,9 +1628,9 @@ overlay_key_handler (GVariant *value, *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); - if (string_value && meta_ui_parse_accelerator (string_value, &combo.keysym, - &combo.keycode, - &combo.modifiers)) + if (string_value && meta_parse_accelerator (string_value, &combo.keysym, + &combo.keycode, + &combo.modifiers)) ; else { @@ -1887,11 +1888,11 @@ update_binding (MetaKeyPref *binding, keycode = 0; mods = 0; - if (!meta_ui_parse_accelerator (strokes[i], &keysym, &keycode, &mods)) + if (!meta_parse_accelerator (strokes[i], &keysym, &keycode, &mods)) { meta_topic (META_DEBUG_KEYBINDINGS, "Failed to parse new GSettings value\n"); - meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"), + meta_warning ("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n", strokes[i], binding->name); /* Value is kept and will thus be removed next time we save the key. diff --git a/src/core/screen-private.h b/src/core/screen-private.h index f6d465c..ef279e5 100644 --- a/src/core/screen-private.h +++ b/src/core/screen-private.h @@ -36,7 +36,7 @@ #include <X11/Xutil.h> #include "stack-tracker.h" #include "ui.h" -#include "monitor-private.h" +#include "meta-monitor-manager.h" typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window, gpointer user_data); @@ -82,8 +82,6 @@ struct _MetaScreen MetaCursorTracker *cursor_tracker; MetaCursor current_cursor; - Window flash_window; - Window wm_sn_selection_window; Atom wm_sn_atom; guint32 wm_sn_timestamp; @@ -118,9 +116,6 @@ struct _MetaScreen guint all_keys_grabbed : 1; int closing; - - /* Managed by compositor.c */ - gpointer compositor_data; /* Instead of unmapping withdrawn windows we can leave them mapped * and restack them below a guard window. When using a compositor @@ -223,12 +218,14 @@ void meta_screen_workspace_switched (MetaScreen *screen, void meta_screen_set_active_workspace_hint (MetaScreen *screen); +void meta_screen_create_guard_window (MetaScreen *screen); + +gboolean meta_screen_handle_xevent (MetaScreen *screen, + XEvent *xevent); + int meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen, int index); int meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen, int index); -gboolean meta_screen_handle_xevent (MetaScreen *screen, - XEvent *xevent); - #endif diff --git a/src/core/screen.c b/src/core/screen.c index ec368b8..2250dee 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -39,7 +39,6 @@ #include "workspace-private.h" #include "keybindings-private.h" #include "stack.h" -#include "xprops.h" #include <meta/compositor.h> #include "mutter-enum-types.h" #include "core.h" @@ -53,6 +52,8 @@ #include <stdio.h> #include <stdlib.h> +#include "x11/xprops.h" + static char* get_screen_name (MetaDisplay *display, int number); @@ -454,6 +455,7 @@ create_guard_window (Display *xdisplay, MetaScreen *screen) XSetWindowAttributes attributes; Window guard_window; gulong create_serial; + MetaStackWindow stack_window; attributes.event_mask = NoEventMask; attributes.override_redirect = True; @@ -488,12 +490,14 @@ create_guard_window (Display *xdisplay, MetaScreen *screen) XISelectEvents (xdisplay, guard_window, &mask, 1); } + stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_window.x11.xwindow = guard_window; meta_stack_tracker_record_add (screen->stack_tracker, - guard_window, + &stack_window, create_serial); meta_stack_tracker_record_lower (screen->stack_tracker, - guard_window, + &stack_window, XNextRequest (xdisplay)); XLowerWindow (xdisplay, guard_window); XMapWindow (xdisplay, guard_window); @@ -559,7 +563,7 @@ meta_screen_new (MetaDisplay *display, } /* We want to find out when the current selection owner dies */ - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); attrs.event_mask = StructureNotifyMask; XChangeWindowAttributes (xdisplay, current_wm_sn_owner, CWEventMask, &attrs); @@ -579,7 +583,7 @@ meta_screen_new (MetaDisplay *display, if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner) { - meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n"), + meta_warning ("Could not acquire window manager selection on screen %d display \"%s\"\n", number, display->name); XDestroyWindow (xdisplay, new_wm_sn_owner); @@ -618,7 +622,7 @@ meta_screen_new (MetaDisplay *display, } /* select our root window events */ - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); /* We need to or with the existing event mask since * gtk+ may be interested in other events. @@ -674,8 +678,9 @@ meta_screen_new (MetaDisplay *display, screen->xscreen = ScreenOfDisplay (xdisplay, number); screen->xroot = xroot; screen->rect.x = screen->rect.y = 0; - - meta_monitor_manager_initialize (); + + if (!meta_is_wayland_compositor ()) + meta_monitor_manager_initialize (); manager = meta_monitor_manager_get (); g_signal_connect (manager, "monitors-changed", @@ -688,7 +693,6 @@ meta_screen_new (MetaDisplay *display, screen->current_cursor = -1; /* invalid/unset */ screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen); screen->default_depth = DefaultDepthOfScreen (screen->xscreen); - screen->flash_window = None; screen->wm_sn_selection_window = new_wm_sn_owner; screen->wm_sn_atom = wm_sn_atom; @@ -706,7 +710,6 @@ meta_screen_new (MetaDisplay *display, screen->columns_of_workspaces = -1; screen->vertical_workspaces = FALSE; screen->starting_corner = META_SCREEN_TOPLEFT; - screen->compositor_data = NULL; screen->guard_window = None; reload_monitor_infos (screen); @@ -807,11 +810,7 @@ meta_screen_free (MetaScreen *screen, meta_display_grab (display); - if (screen->display->compositor) - { - meta_compositor_unmanage_screen (screen->display->compositor, - screen); - } + meta_compositor_unmanage (screen->display->compositor); meta_display_unmanage_windows_for_screen (display, screen, timestamp); @@ -842,10 +841,10 @@ meta_screen_free (MetaScreen *screen, meta_stack_free (screen->stack); meta_stack_tracker_free (screen->stack_tracker); - meta_error_trap_push_with_return (screen->display); + meta_error_trap_push (screen->display); XSelectInput (screen->display->xdisplay, screen->xroot, 0); if (meta_error_trap_pop_with_return (screen->display) != Success) - meta_warning (_("Could not release screen %d on display \"%s\"\n"), + meta_warning ("Could not release screen %d on display \"%s\"\n", screen->number, screen->display->name); unset_wm_check_hint (screen); @@ -873,54 +872,35 @@ meta_screen_free (MetaScreen *screen, } void +meta_screen_create_guard_window (MetaScreen *screen) +{ + if (screen->guard_window == None) + screen->guard_window = create_guard_window (screen->display->xdisplay, screen); +} + +void meta_screen_manage_all_windows (MetaScreen *screen) { - Window *_children; - Window *children; + MetaStackWindow *_children; + MetaStackWindow *children; int n_children, i; - if (screen->guard_window == None) - screen->guard_window = create_guard_window (screen->display->xdisplay, - screen); - meta_stack_freeze (screen->stack); meta_stack_tracker_get_stack (screen->stack_tracker, &_children, &n_children); /* Copy the stack as it will be modified as part of the loop */ - children = g_memdup (_children, sizeof (Window) * n_children); + children = g_memdup (_children, sizeof (MetaStackWindow) * n_children); for (i = 0; i < n_children; ++i) { - meta_window_new (screen->display, children[i], TRUE, - META_COMP_EFFECT_NONE); + meta_window_x11_new (screen->display, children[i].x11.xwindow, TRUE, + META_COMP_EFFECT_NONE); } g_free (children); meta_stack_thaw (screen->stack); } -/** - * meta_screen_for_x_screen: - * @xscreen: an X screen structure. - * - * Gets the #MetaScreen corresponding to an X screen structure. - * - * Return value: (transfer none): the #MetaScreen for the X screen - * %NULL if Metacity is not managing the screen. - */ -MetaScreen* -meta_screen_for_x_screen (Screen *xscreen) -{ - MetaDisplay *display; - - display = meta_display_for_x_display (DisplayOfScreen (xscreen)); - - if (display == NULL) - return NULL; - - return meta_display_screen_for_x_screen (display, xscreen); -} - static void prefs_changed_callback (MetaPreference pref, gpointer data) @@ -1405,6 +1385,26 @@ update_focus_mode (MetaScreen *screen) } void +meta_screen_update_cursor (MetaScreen *screen) +{ + MetaDisplay *display = screen->display; + MetaCursor cursor = screen->current_cursor; + Cursor xcursor; + MetaCursorReference *cursor_ref; + + cursor_ref = meta_cursor_reference_from_theme (screen->cursor_tracker, cursor); + meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor_ref); + meta_cursor_reference_unref (cursor_ref); + + /* Set a cursor for X11 applications that don't specify their own */ + xcursor = meta_display_create_x_cursor (display, cursor); + + XDefineCursor (display->xdisplay, screen->xroot, xcursor); + XFlush (display->xdisplay); + XFreeCursor (display->xdisplay, xcursor); +} + +void meta_screen_set_cursor (MetaScreen *screen, MetaCursor cursor) { @@ -1412,14 +1412,7 @@ meta_screen_set_cursor (MetaScreen *screen, return; screen->current_cursor = cursor; - meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor); -} - -void -meta_screen_update_cursor (MetaScreen *screen) -{ - meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, - screen->current_cursor); + meta_screen_update_cursor (screen); } static gboolean @@ -1460,11 +1453,10 @@ meta_screen_update_tile_preview_timeout (gpointer data) monitor = meta_window_get_current_tile_monitor_number (window); meta_window_get_current_tile_area (window, &tile_rect); meta_compositor_show_tile_preview (screen->display->compositor, - screen, window, &tile_rect, monitor); + window, &tile_rect, monitor); } else - meta_compositor_hide_tile_preview (screen->display->compositor, - screen); + meta_compositor_hide_tile_preview (screen->display->compositor); return FALSE; } @@ -1500,8 +1492,7 @@ meta_screen_hide_tile_preview (MetaScreen *screen) if (screen->tile_preview_timeout_id > 0) g_source_remove (screen->tile_preview_timeout_id); - meta_compositor_hide_tile_preview (screen->display->compositor, - screen); + meta_compositor_hide_tile_preview (screen->display->compositor); } MetaWindow* @@ -1509,38 +1500,19 @@ meta_screen_get_mouse_window (MetaScreen *screen, MetaWindow *not_this_one) { MetaWindow *window; - Window root_return, child_return; - double root_x_return, root_y_return; - double win_x_return, win_y_return; - XIButtonState buttons; - XIModifierState mods; - XIGroupState group; + int x, y; if (not_this_one) meta_topic (META_DEBUG_FOCUS, "Focusing mouse window excluding %s\n", not_this_one->desc); - meta_error_trap_push (screen->display); - XIQueryPointer (screen->display->xdisplay, - META_VIRTUAL_CORE_POINTER_ID, - screen->xroot, - &root_return, - &child_return, - &root_x_return, - &root_y_return, - &win_x_return, - &win_y_return, - &buttons, - &mods, - &group); - meta_error_trap_pop (screen->display); - free (buttons.mask); + meta_cursor_tracker_get_pointer (screen->cursor_tracker, + &x, &y, NULL); window = meta_stack_get_default_focus_window_at_point (screen->stack, screen->active_workspace, not_this_one, - root_x_return, - root_y_return); + x, y); return window; } @@ -1822,28 +1794,11 @@ meta_screen_get_current_monitor (MetaScreen *screen) if (screen->display->monitor_cache_invalidated) { - Window root_return, child_return; - double win_x_return, win_y_return; - double root_x_return, root_y_return; - XIButtonState buttons; - XIModifierState mods; - XIGroupState group; - - XIQueryPointer (screen->display->xdisplay, - META_VIRTUAL_CORE_POINTER_ID, - screen->xroot, - &root_return, - &child_return, - &root_x_return, - &root_y_return, - &win_x_return, - &win_y_return, - &buttons, - &mods, - &group); - free (buttons.mask); - - meta_screen_get_current_monitor_for_pos (screen, root_x_return, root_y_return); + int x, y; + + meta_cursor_tracker_get_pointer (screen->cursor_tracker, + &x, &y, NULL); + meta_screen_get_current_monitor_for_pos (screen, x, y); } return screen->last_monitor_index; @@ -2554,10 +2509,8 @@ on_monitors_changed (MetaMonitorManager *manager, &changes); } - if (screen->display->compositor) - meta_compositor_sync_screen_size (screen->display->compositor, - screen, - screen->rect.width, screen->rect.height); + meta_compositor_sync_screen_size (screen->display->compositor, + screen->rect.width, screen->rect.height); /* Queue a resize on all the windows */ meta_screen_foreach_window (screen, meta_screen_resize_func, 0); @@ -3097,24 +3050,6 @@ meta_screen_get_size (MetaScreen *screen, *height = screen->rect.height; } -/** - * meta_screen_get_compositor_data: (skip) - * @screen: A #MetaScreen - * - */ -gpointer -meta_screen_get_compositor_data (MetaScreen *screen) -{ - return screen->compositor_data; -} - -void -meta_screen_set_compositor_data (MetaScreen *screen, - gpointer compositor) -{ - screen->compositor_data = compositor; -} - void meta_screen_set_cm_selection (MetaScreen *screen) { @@ -3373,10 +3308,6 @@ gboolean meta_screen_handle_xevent (MetaScreen *screen, XEvent *xevent) { - /* Go through our helpers and see if they want this event. - Currently, only MetaCursorTracker. - */ - if (meta_cursor_tracker_handle_xevent (screen->cursor_tracker, xevent)) return TRUE; diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c index 17979e3..77266a0 100644 --- a/src/core/stack-tracker.c +++ b/src/core/stack-tracker.c @@ -96,28 +96,29 @@ union _MetaStackOp struct { MetaStackOpType type; gulong serial; + MetaStackWindow window; } any; struct { MetaStackOpType type; gulong serial; - Window window; + MetaStackWindow window; } add; struct { MetaStackOpType type; gulong serial; - Window window; + MetaStackWindow window; } remove; struct { MetaStackOpType type; gulong serial; - Window window; - Window sibling; + MetaStackWindow window; + MetaStackWindow sibling; } raise_above; struct { MetaStackOpType type; gulong serial; - Window window; - Window sibling; + MetaStackWindow window; + MetaStackWindow sibling; } lower_below; }; @@ -128,20 +129,25 @@ struct _MetaStackTracker /* This is the last state of the stack as based on events received * from the X server. */ - GArray *server_stack; + GArray *xserver_stack; /* This is the serial of the last request we made that was reflected - * in server_stack + * in xserver_stack */ - gulong server_serial; + gulong xserver_serial; + + /* A combined stack containing X and Wayland windows but without + * any unverified operations applied. */ + GArray *verified_stack; /* This is a queue of requests we've made to change the stacking order, * where we haven't yet gotten a reply back from the server. */ - GQueue *queued_requests; + GQueue *unverified_predictions; - /* This is how we think the stack is, based on server_stack, and - * on requests we've made subsequent to server_stack + /* This is how we think the stack is, based on verified_stack, and + * on the unverified_predictions we've made subsequent to + * verified_stack. */ GArray *predicted_stack; @@ -151,36 +157,81 @@ struct _MetaStackTracker guint sync_stack_later; }; +static gboolean +meta_stack_window_is_set (const MetaStackWindow *window) +{ + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) + return window->x11.xwindow == None ? FALSE : TRUE; + else + return window->wayland.meta_window ? TRUE : FALSE; +} + +gboolean +meta_stack_window_equal (const MetaStackWindow *a, + const MetaStackWindow *b) +{ + if (a->any.type == b->any.type) + { + if (a->any.type == META_WINDOW_CLIENT_TYPE_X11) + return a->x11.xwindow == b->x11.xwindow; + else + return a->wayland.meta_window == b->wayland.meta_window; + } + else + return FALSE; +} + +static char * +get_window_id (MetaStackWindow *window) +{ + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) + return g_strdup_printf ("X11:%lx", window->x11.xwindow); + else + return g_strdup_printf ("Wayland:%p", window->wayland.meta_window); +} + static void meta_stack_op_dump (MetaStackOp *op, const char *prefix, const char *suffix) { + char *window_id = get_window_id (&op->any.window); + switch (op->any.type) { case STACK_OP_ADD: - meta_topic (META_DEBUG_STACK, "%sADD(%#lx; %ld)%s", - prefix, op->add.window, op->any.serial, suffix); + meta_topic (META_DEBUG_STACK, "%sADD(%s; %ld)%s", + prefix, window_id, op->any.serial, suffix); break; case STACK_OP_REMOVE: - meta_topic (META_DEBUG_STACK, "%sREMOVE(%#lx; %ld)%s", - prefix, op->add.window, op->any.serial, suffix); + meta_topic (META_DEBUG_STACK, "%sREMOVE(%s; %ld)%s", + prefix, window_id, op->any.serial, suffix); break; case STACK_OP_RAISE_ABOVE: - meta_topic (META_DEBUG_STACK, "%sRAISE_ABOVE(%#lx, %#lx; %ld)%s", - prefix, - op->raise_above.window, op->raise_above.sibling, - op->any.serial, - suffix); - break; + { + char *sibling_id = get_window_id (&op->raise_above.sibling); + meta_topic (META_DEBUG_STACK, "%sRAISE_ABOVE(%s, %s; %ld)%s", + prefix, + window_id, sibling_id, + op->any.serial, + suffix); + g_free (sibling_id); + break; + } case STACK_OP_LOWER_BELOW: - meta_topic (META_DEBUG_STACK, "%sLOWER_BELOW(%#lx, %#lx; %ld)%s", - prefix, - op->lower_below.window, op->lower_below.sibling, - op->any.serial, - suffix); - break; + { + char *sibling_id = get_window_id (&op->lower_below.sibling); + meta_topic (META_DEBUG_STACK, "%sLOWER_BELOW(%s, %s; %ld)%s", + prefix, + window_id, sibling_id, + op->any.serial, + suffix); + g_free (sibling_id); + break; + } } + + g_free (window_id); } static void @@ -191,23 +242,42 @@ meta_stack_tracker_dump (MetaStackTracker *tracker) meta_topic (META_DEBUG_STACK, "MetaStackTracker state (screen=%d)\n", tracker->screen->number); meta_push_no_msg_prefix (); - meta_topic (META_DEBUG_STACK, " server_serial: %ld\n", tracker->server_serial); - meta_topic (META_DEBUG_STACK, " server_stack: "); - for (i = 0; i < tracker->server_stack->len; i++) - meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->server_stack, Window, i)); - if (tracker->predicted_stack) + meta_topic (META_DEBUG_STACK, " xserver_serial: %ld\n", tracker->xserver_serial); + meta_topic (META_DEBUG_STACK, " xserver_stack: "); + for (i = 0; i < tracker->xserver_stack->len; i++) { - meta_topic (META_DEBUG_STACK, "\n predicted_stack: "); - for (i = 0; i < tracker->predicted_stack->len; i++) - meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->predicted_stack, Window, i)); + MetaStackWindow *window = &g_array_index (tracker->xserver_stack, MetaStackWindow, i); + char *window_id = get_window_id (window); + meta_topic (META_DEBUG_STACK, " %s", window_id); + g_free (window_id); + } + meta_topic (META_DEBUG_STACK, "\n verfied_stack: "); + for (i = 0; i < tracker->verified_stack->len; i++) + { + MetaStackWindow *window = &g_array_index (tracker->verified_stack, MetaStackWindow, i); + char *window_id = get_window_id (window); + meta_topic (META_DEBUG_STACK, " %s", window_id); + g_free (window_id); } - meta_topic (META_DEBUG_STACK, "\n queued_requests: ["); - for (l = tracker->queued_requests->head; l; l = l->next) + meta_topic (META_DEBUG_STACK, "\n unverified_predictions: ["); + for (l = tracker->unverified_predictions->head; l; l = l->next) { MetaStackOp *op = l->data; meta_stack_op_dump (op, "", l->next ? ", " : ""); } meta_topic (META_DEBUG_STACK, "]\n"); + if (tracker->predicted_stack) + { + meta_topic (META_DEBUG_STACK, "\n predicted_stack: "); + for (i = 0; i < tracker->predicted_stack->len; i++) + { + MetaStackWindow *window = &g_array_index (tracker->predicted_stack, MetaStackWindow, i); + char *window_id = get_window_id (window); + meta_topic (META_DEBUG_STACK, " %s", window_id); + g_free (window_id); + } + } + meta_topic (META_DEBUG_STACK, "\n"); meta_pop_no_msg_prefix (); } @@ -218,42 +288,57 @@ meta_stack_op_free (MetaStackOp *op) } static int -find_window (GArray *stack, - Window window) +find_window (GArray *window_stack, + MetaStackWindow *window) { guint i; - for (i = 0; i < stack->len; i++) - if (g_array_index (stack, Window, i) == window) - return i; + for (i = 0; i < window_stack->len; i++) + { + MetaStackWindow *current = &g_array_index (window_stack, MetaStackWindow, i); + if (current->any.type == window->any.type) + { + if (current->any.type == META_WINDOW_CLIENT_TYPE_X11 && + current->x11.xwindow == window->x11.xwindow) + return i; + else + if (current->wayland.meta_window == window->wayland.meta_window) + return i; + } + } return -1; } /* Returns TRUE if stack was changed */ static gboolean -move_window_above (GArray *stack, - Window window, - int old_pos, - int above_pos) +move_window_above (GArray *stack, + MetaStackWindow *window, + int old_pos, + int above_pos) { + /* Copy the window by-value before we start shifting things around + * in the stack in case window points into the stack itself. */ + MetaStackWindow window_val = *window; int i; if (old_pos < above_pos) { for (i = old_pos; i < above_pos; i++) - g_array_index (stack, Window, i) = g_array_index (stack, Window, i + 1); + g_array_index (stack, MetaStackWindow, i) = + g_array_index (stack, MetaStackWindow, i + 1); - g_array_index (stack, Window, above_pos) = window; + g_array_index (stack, MetaStackWindow, above_pos) = window_val; return TRUE; } else if (old_pos > above_pos + 1) { for (i = old_pos; i > above_pos + 1; i--) - g_array_index (stack, Window, i) = g_array_index (stack, Window, i - 1); + g_array_index (stack, MetaStackWindow, i) = + g_array_index (stack, MetaStackWindow, i - 1); - g_array_index (stack, Window, above_pos + 1) = window; + g_array_index (stack, MetaStackWindow, above_pos + 1) = window_val; return TRUE; } @@ -270,11 +355,13 @@ meta_stack_op_apply (MetaStackOp *op, { case STACK_OP_ADD: { - int old_pos = find_window (stack, op->add.window); + int old_pos = find_window (stack, &op->add.window); if (old_pos >= 0) { - g_warning ("STACK_OP_ADD: window %#lx already in stack", - op->add.window); + char *window_id = get_window_id (&op->add.window); + g_warning ("STACK_OP_ADD: window %s already in stack", + window_id); + g_free (window_id); return FALSE; } @@ -283,11 +370,13 @@ meta_stack_op_apply (MetaStackOp *op, } case STACK_OP_REMOVE: { - int old_pos = find_window (stack, op->remove.window); + int old_pos = find_window (stack, &op->remove.window); if (old_pos < 0) { - g_warning ("STACK_OP_REMOVE: window %#lx not in stack", - op->remove.window); + char *window_id = get_window_id (&op->remove.window); + g_warning ("STACK_OP_REMOVE: window %s not in stack", + window_id); + g_free (window_id); return FALSE; } @@ -296,22 +385,26 @@ meta_stack_op_apply (MetaStackOp *op, } case STACK_OP_RAISE_ABOVE: { - int old_pos = find_window (stack, op->raise_above.window); + int old_pos = find_window (stack, &op->raise_above.window); int above_pos; if (old_pos < 0) { - g_warning ("STACK_OP_RAISE_ABOVE: window %#lx not in stack", - op->raise_above.window); + char *window_id = get_window_id (&op->raise_above.window); + g_warning ("STACK_OP_RAISE_ABOVE: window %s not in stack", + window_id); + g_free (window_id); return FALSE; } - if (op->raise_above.sibling != None) + if (meta_stack_window_is_set (&op->raise_above.sibling)) { - above_pos = find_window (stack, op->raise_above.sibling); + above_pos = find_window (stack, &op->raise_above.sibling); if (above_pos < 0) { - g_warning ("STACK_OP_RAISE_ABOVE: sibling window %#lx not in stack", - op->raise_above.sibling); + char *sibling_id = get_window_id (&op->raise_above.sibling); + g_warning ("STACK_OP_RAISE_ABOVE: sibling window %s not in stack", + sibling_id); + g_free (sibling_id); return FALSE; } } @@ -320,26 +413,30 @@ meta_stack_op_apply (MetaStackOp *op, above_pos = -1; } - return move_window_above (stack, op->raise_above.window, old_pos, above_pos); + return move_window_above (stack, &op->raise_above.window, old_pos, above_pos); } case STACK_OP_LOWER_BELOW: { - int old_pos = find_window (stack, op->lower_below.window); + int old_pos = find_window (stack, &op->lower_below.window); int above_pos; if (old_pos < 0) { - g_warning ("STACK_OP_LOWER_BELOW: window %#lx not in stack", - op->lower_below.window); + char *window_id = get_window_id (&op->lower_below.window); + g_warning ("STACK_OP_LOWER_BELOW: window %s not in stack", + window_id); + g_free (window_id); return FALSE; } - if (op->lower_below.sibling != None) + if (meta_stack_window_is_set (&op->lower_below.sibling)) { - int below_pos = find_window (stack, op->lower_below.sibling); + int below_pos = find_window (stack, &op->lower_below.sibling); if (below_pos < 0) { - g_warning ("STACK_OP_LOWER_BELOW: sibling window %#lx not in stack", - op->lower_below.sibling); + char *sibling_id = get_window_id (&op->lower_below.sibling); + g_warning ("STACK_OP_LOWER_BELOW: sibling window %s not in stack", + sibling_id); + g_free (sibling_id); return FALSE; } @@ -350,7 +447,7 @@ meta_stack_op_apply (MetaStackOp *op, above_pos = stack->len - 1; } - return move_window_above (stack, op->lower_below.window, old_pos, above_pos); + return move_window_above (stack, &op->lower_below.window, old_pos, above_pos); } } @@ -359,37 +456,65 @@ meta_stack_op_apply (MetaStackOp *op, } static GArray * -copy_stack (Window *windows, - guint n_windows) +copy_stack (GArray *stack) { - GArray *stack = g_array_new (FALSE, FALSE, sizeof (Window)); + GArray *copy = g_array_sized_new (FALSE, FALSE, sizeof (MetaStackWindow), stack->len); - g_array_set_size (stack, n_windows); - memcpy (stack->data, windows, sizeof (Window) * n_windows); + g_array_set_size (copy, stack->len); - return stack; + memcpy (copy->data, stack->data, sizeof (MetaStackWindow) * stack->len); + + return copy; } -MetaStackTracker * -meta_stack_tracker_new (MetaScreen *screen) +static void +requery_xserver_stack (MetaStackTracker *tracker) { - MetaStackTracker *tracker; + MetaScreen *screen = tracker->screen; Window ignored1, ignored2; Window *children; guint n_children; + guint i; - tracker = g_new0 (MetaStackTracker, 1); - tracker->screen = screen; + if (tracker->xserver_stack) + g_array_free (tracker->xserver_stack, TRUE); - tracker->server_serial = XNextRequest (screen->display->xdisplay); + tracker->xserver_serial = XNextRequest (screen->display->xdisplay); XQueryTree (screen->display->xdisplay, screen->xroot, &ignored1, &ignored2, &children, &n_children); - tracker->server_stack = copy_stack (children, n_children); + + tracker->xserver_stack = + g_array_sized_new (FALSE, FALSE, sizeof (MetaStackWindow), n_children); + g_array_set_size (tracker->xserver_stack, n_children); + + for (i = 0; i < n_children; i++) + { + MetaStackWindow *window = + &g_array_index (tracker->xserver_stack, MetaStackWindow, i); + window->any.type = META_WINDOW_CLIENT_TYPE_X11; + window->x11.xwindow = children[i]; + } + XFree (children); +} + +MetaStackTracker * +meta_stack_tracker_new (MetaScreen *screen) +{ + MetaStackTracker *tracker; + + tracker = g_new0 (MetaStackTracker, 1); + tracker->screen = screen; + + requery_xserver_stack (tracker); + + tracker->verified_stack = copy_stack (tracker->xserver_stack); - tracker->queued_requests = g_queue_new (); + tracker->unverified_predictions = g_queue_new (); + + meta_stack_tracker_dump (tracker); return tracker; } @@ -400,23 +525,38 @@ meta_stack_tracker_free (MetaStackTracker *tracker) if (tracker->sync_stack_later) meta_later_remove (tracker->sync_stack_later); - g_array_free (tracker->server_stack, TRUE); + g_array_free (tracker->xserver_stack, TRUE); + g_array_free (tracker->verified_stack, TRUE); if (tracker->predicted_stack) g_array_free (tracker->predicted_stack, TRUE); - g_queue_foreach (tracker->queued_requests, (GFunc)meta_stack_op_free, NULL); - g_queue_free (tracker->queued_requests); - tracker->queued_requests = NULL; + g_queue_foreach (tracker->unverified_predictions, (GFunc)meta_stack_op_free, NULL); + g_queue_free (tracker->unverified_predictions); + tracker->unverified_predictions = NULL; g_free (tracker); } static void -stack_tracker_queue_request (MetaStackTracker *tracker, - MetaStackOp *op) +stack_tracker_apply_prediction (MetaStackTracker *tracker, + MetaStackOp *op) { - meta_stack_op_dump (op, "Queueing: ", "\n"); - g_queue_push_tail (tracker->queued_requests, op); + /* If this is a wayland operation then it's implicitly verified so + * we can apply it immediately so long as it doesn't depend on any + * unverified X operations... + */ + if (op->any.window.any.type == META_WINDOW_CLIENT_TYPE_WAYLAND && + tracker->unverified_predictions->length == 0) + { + if (meta_stack_op_apply (op, tracker->verified_stack)) + meta_stack_tracker_queue_sync_stack (tracker); + } + else + { + meta_stack_op_dump (op, "Predicting: ", "\n"); + g_queue_push_tail (tracker->unverified_predictions, op); + } + if (!tracker->predicted_stack || meta_stack_op_apply (op, tracker->predicted_stack)) meta_stack_tracker_queue_sync_stack (tracker); @@ -425,44 +565,50 @@ stack_tracker_queue_request (MetaStackTracker *tracker, } void -meta_stack_tracker_record_add (MetaStackTracker *tracker, - Window window, - gulong serial) +meta_stack_tracker_record_add (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_ADD; op->any.serial = serial; - op->add.window = window; + op->any.window = *window; - stack_tracker_queue_request (tracker, op); + stack_tracker_apply_prediction (tracker, op); } void -meta_stack_tracker_record_remove (MetaStackTracker *tracker, - Window window, - gulong serial) +meta_stack_tracker_record_remove (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_REMOVE; op->any.serial = serial; - op->remove.window = window; + op->any.window = *window; - stack_tracker_queue_request (tracker, op); + stack_tracker_apply_prediction (tracker, op); } void -meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, - Window *windows, - int n_windows, - gulong serial) +meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, + const MetaStackWindow *windows, + int n_windows, + gulong serial) { int i; + int n_x_windows = 0; /* XRestackWindows() isn't actually a X requests - it's broken down * by XLib into a series of XConfigureWindow(StackMode=below); we - * mirror that exactly here. + * mirror that here. + * + * Since there may be a mixture of X and wayland windows in the + * stack it's ambiguous which operations we should associate with an + * X serial number. One thing we do know though is that there will + * be (n_x_window - 1) X requests made. * * Aside: Having a separate StackOp for this would be possible to * get some extra efficiency in memory allocation and in applying @@ -471,79 +617,406 @@ meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, * events with intermediate serials, set n_complete rather than * removing the op from the queue. */ + if (n_windows && windows[0].any.type == META_WINDOW_CLIENT_TYPE_X11) + n_x_windows++; for (i = 0; i < n_windows - 1; i++) - meta_stack_tracker_record_lower_below (tracker, windows[i + 1], windows[i], - serial + i); + { + const MetaStackWindow *lower = &windows[i + 1]; + gboolean involves_x = FALSE; + + if (lower->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + n_x_windows++; + + /* Since the first X window is a reference point we only + * assoicate a serial number with the operations involving + * later X windows. */ + if (n_x_windows > 1) + involves_x = TRUE; + } + + meta_stack_tracker_record_lower_below (tracker, lower, &windows[i], + involves_x ? serial++ : 0); + } } void -meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, - Window window, - Window sibling, - gulong serial) +meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, + const MetaStackWindow *window, + const MetaStackWindow *sibling, + gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_RAISE_ABOVE; op->any.serial = serial; - op->raise_above.window = window; - op->raise_above.sibling = sibling; + op->any.window = *window; + if (sibling) + op->raise_above.sibling = *sibling; + else + { + op->raise_above.sibling.any.type = META_WINDOW_CLIENT_TYPE_X11; + op->raise_above.sibling.x11.xwindow = None; + } - stack_tracker_queue_request (tracker, op); + stack_tracker_apply_prediction (tracker, op); } void -meta_stack_tracker_record_lower_below (MetaStackTracker *tracker, - Window window, - Window sibling, - gulong serial) +meta_stack_tracker_record_lower_below (MetaStackTracker *tracker, + const MetaStackWindow *window, + const MetaStackWindow *sibling, + gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_LOWER_BELOW; op->any.serial = serial; - op->lower_below.window = window; - op->lower_below.sibling = sibling; + op->any.window = *window; + if (sibling) + op->lower_below.sibling = *sibling; + else + { + op->lower_below.sibling.any.type = META_WINDOW_CLIENT_TYPE_X11; + op->lower_below.sibling.x11.xwindow = None; + } - stack_tracker_queue_request (tracker, op); + stack_tracker_apply_prediction (tracker, op); } void -meta_stack_tracker_record_lower (MetaStackTracker *tracker, - Window window, - gulong serial) +meta_stack_tracker_record_lower (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial) { - meta_stack_tracker_record_raise_above (tracker, window, None, serial); + meta_stack_tracker_record_raise_above (tracker, window, NULL, serial); } -static void -stack_tracker_event_received (MetaStackTracker *tracker, - MetaStackOp *op) +/* @op is an operation derived from an X event from the server and we + * want to verify that our predicted operations are consistent with + * what's being reported by the X server. + * + * NB: Since our stack may actually be a mixture of X and Wayland + * clients we can't simply apply these operations derived from X + * events onto our stack and discard old predictions because these + * operations aren't aware of wayland windows. + * + * This function applies all the unverified predicted operations up to + * the given @serial onto the verified_stack so that we can check the + * stack for consistency with the given X operation. + * + * Return value: %TRUE if the predicted state is consistent with + * receiving the given @op from X, else %FALSE. + * + * @modified will be set to %TRUE if tracker->verified_stack is + * changed by applying any newly validated operations, else %FALSE. + */ +static gboolean +stack_tracker_verify_predictions (MetaStackTracker *tracker, + MetaStackOp *op, + gboolean *modified) { - gboolean need_sync = FALSE; + GArray *tmp_predicted_stack = NULL; + GArray *predicted_stack; + gboolean modified_stack = FALSE; - meta_stack_op_dump (op, "Stack op event received: ", "\n"); + /* Wayland operations don't need to be verified and shouldn't end up + * passed to this api. */ + g_return_val_if_fail (op->any.window.any.type == META_WINDOW_CLIENT_TYPE_X11, FALSE); + + if (tracker->unverified_predictions->length) + { + GList *l; - if (op->any.serial < tracker->server_serial) - return; + tmp_predicted_stack = predicted_stack = copy_stack (tracker->verified_stack); + + for (l = tracker->unverified_predictions->head; l; l = l->next) + { + MetaStackOp *current_op = l->data; + + if (current_op->any.serial > op->any.serial) + break; + + modified_stack |= meta_stack_op_apply (current_op, predicted_stack); + } + } + else + predicted_stack = tracker->verified_stack; - tracker->server_serial = op->any.serial; + switch (op->any.type) + { + case STACK_OP_ADD: + if (!find_window (predicted_stack, &op->any.window)) + { + char *window_id = get_window_id (&op->any.window); + meta_topic (META_DEBUG_STACK, "Verify STACK_OP_ADD: window %s not found\n", + window_id); + g_free (window_id); + goto not_verified; + } + break; + case STACK_OP_REMOVE: + if (find_window (predicted_stack, &op->any.window)) + { + char *window_id = get_window_id (&op->any.window); + meta_topic (META_DEBUG_STACK, "Verify STACK_OP_REMOVE: window %s was unexpectedly found\n", + window_id); + g_free (window_id); + goto not_verified; + } + break; + case STACK_OP_RAISE_ABOVE: + { + Window last_xwindow = None; + char *window_id; + unsigned int i; + + /* This code is only intended for verifying operations based + * on XEvents where we can assume the sibling refers to + * another X window... */ + g_return_val_if_fail (op->raise_above.sibling.any.type == + META_WINDOW_CLIENT_TYPE_X11, FALSE); + + for (i = 0; i < predicted_stack->len; i++) + { + MetaStackWindow *window = &g_array_index (predicted_stack, MetaStackWindow, i); + + if (meta_stack_window_equal (window, &op->any.window)) + { + if (last_xwindow == op->raise_above.sibling.x11.xwindow) + goto verified; + else + goto not_verified; + } + + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) + last_xwindow = window->x11.xwindow; + } + + window_id = get_window_id (&op->any.window); + meta_topic (META_DEBUG_STACK, "Verify STACK_OP_RAISE_ABOVE: window %s not found\n", + window_id); + g_free (window_id); + goto not_verified; + } + case STACK_OP_LOWER_BELOW: + g_warn_if_reached (); /* No X events currently lead to this path */ + goto not_verified; + } - if (meta_stack_op_apply (op, tracker->server_stack)) - need_sync = TRUE; +verified: - while (tracker->queued_requests->head) + /* We can free the operations which we have now verified... */ + while (tracker->unverified_predictions->head) { - MetaStackOp *queued_op = tracker->queued_requests->head->data; + MetaStackOp *queued_op = tracker->unverified_predictions->head->data; + if (queued_op->any.serial > op->any.serial) break; - g_queue_pop_head (tracker->queued_requests); + g_queue_pop_head (tracker->unverified_predictions); meta_stack_op_free (queued_op); - need_sync = TRUE; } - if (need_sync) + *modified = modified_stack; + if (modified_stack) + { + g_array_free (tracker->verified_stack, TRUE); + tracker->verified_stack = predicted_stack; + } + else if (tmp_predicted_stack) + g_array_free (tmp_predicted_stack, TRUE); + + return TRUE; + +not_verified: + + if (tmp_predicted_stack) + g_array_free (tmp_predicted_stack, TRUE); + + if (tracker->predicted_stack) + { + g_array_free (tracker->predicted_stack, TRUE); + tracker->predicted_stack = NULL; + } + + *modified = FALSE; + + return FALSE; +} + +/* If we find that our predicted state is not consistent with what the + * X server is reporting to us then this function can re-query and + * re-synchronize verified_stack with the X server stack while + * hopefully not disrupting the relative stacking of Wayland windows. + * + * Return value: %TRUE if the verified stack was modified with respect + * to the predicted stack else %FALSE. + * + * Note: ->predicted_stack will be cleared by this function if + * ->verified_stack had to be modified when re-synchronizing. + */ +static gboolean +resync_verified_stack_with_xserver_stack (MetaStackTracker *tracker) +{ + GList *l; + unsigned int i, j; + MetaStackWindow *expected_xwindow; + gboolean modified_stack; + + /* Overview of the algorithm: + * + * - Re-query the complete X window stack from the X server via + * XQueryTree() and update xserver_stack. + * + * - Apply all operations in unverified_predictions to + * verified_stack so we have a predicted stack including Wayland + * windows and free the queue of unverified_predictions. + * + * - Iterate through the x windows listed in verified_stack at the + * same time as iterating the windows in xserver_list. (Stop + * when we reach the end of the xserver_list) + * - If the window found doesn't match the window expected + * according to the order of xserver_list then: + * - Look ahead for the window we were expecting and restack + * that above the previous X window. If we fail to find the + * expected window then create a new entry for it and stack + * that. + * + * - Continue to iterate through verified_stack for any remaining + * X windows that we now know aren't in the xserver_list and + * remove them. + * + * - Free ->predicted_stack if any. + */ + + meta_topic (META_DEBUG_STACK, "Fully re-synchronizing X stack with verified stack\n"); + + requery_xserver_stack (tracker); + + for (l = tracker->unverified_predictions->head; l; l = l->next) + meta_stack_op_apply (l->data, tracker->verified_stack); + g_queue_clear (tracker->unverified_predictions); + + j = 0; + expected_xwindow = + &g_array_index (tracker->xserver_stack, MetaStackWindow, j); + + for (i = 0; + i < tracker->verified_stack->len; + ) + { + MetaStackWindow *current = + &g_array_index (tracker->verified_stack, MetaStackWindow, i); + + if (current->any.type != META_WINDOW_CLIENT_TYPE_X11) + { + /* Progress i but not j */ + i++; + continue; + } + + if (current->x11.xwindow != expected_xwindow->x11.xwindow) + { + MetaStackWindow new; + MetaStackWindow *expected; + int expected_index; + + /* If the current window corresponds to a window that's not + * in xserver_stack any more then the least disruptive thing + * we can do is to simply remove it and take another look at + * the same index. + * + * Note: we didn't used to do this and instead relied on + * removed windows getting pushed to the end of the list so + * they could all be removed together but this also resulted + * in pushing Wayland windows to the end too, disrupting + * their positioning relative to X windows too much. + * + * Technically we only need to look forward from j if we + * wanted to optimize this a bit... + */ + if (find_window (tracker->xserver_stack, current) < 0) + { + g_array_remove_index (tracker->verified_stack, i); + continue; + } + + /* Technically we only need to look forward from i if we + * wanted to optimize this a bit... */ + expected_index = + find_window (tracker->verified_stack, expected_xwindow); + + if (expected_index >= 0) + { + expected = &g_array_index (tracker->verified_stack, + MetaStackWindow, expected_index); + } + else + { + new.any.type = META_WINDOW_CLIENT_TYPE_X11; + new.x11.xwindow = expected_xwindow->x11.xwindow; + + g_array_append_val (tracker->verified_stack, new); + + expected = &new; + expected_index = tracker->verified_stack->len - 1; + } + + /* Note: that this move will effectively bump the index of + * the current window. + * + * We want to continue by re-checking this window against + * the next expected window though so we don't have to + * update i to compensate here. + */ + move_window_above (tracker->verified_stack, expected, + expected_index, /* current index */ + i - 1); /* above */ + modified_stack = TRUE; + } + + /* NB: we want to make sure that if we break the loop because j + * reaches the end of xserver_stack that i has also been + * incremented already so that we can run a final loop to remove + * remaining windows based on the i index. */ + i++; + + j++; + expected_xwindow = + &g_array_index (tracker->xserver_stack, MetaStackWindow, j); + + if (j >= tracker->xserver_stack->len) + break; + } + + /* We now know that any remaining X windows aren't listed in the + * xserver_stack and so we can remove them. */ + while (i < tracker->verified_stack->len) + { + MetaStackWindow *current = + &g_array_index (tracker->verified_stack, MetaStackWindow, i); + + if (current->any.type == META_WINDOW_CLIENT_TYPE_X11) + g_array_remove_index (tracker->verified_stack, i); + else + i++; + + modified_stack = TRUE; + } + + /* If we get to the end of verified_list and there are any remaining + * entries in xserver_list then append them all to the end */ + for (; j < tracker->xserver_stack->len; j++) + { + MetaStackWindow *current = + &g_array_index (tracker->xserver_stack, MetaStackWindow, j); + g_array_append_val (tracker->verified_stack, *current); + + modified_stack = TRUE; + } + + if (modified_stack) { if (tracker->predicted_stack) { @@ -554,6 +1027,47 @@ stack_tracker_event_received (MetaStackTracker *tracker, meta_stack_tracker_queue_sync_stack (tracker); } + return modified_stack; +} + +static void +stack_tracker_event_received (MetaStackTracker *tracker, + MetaStackOp *op) +{ + gboolean need_sync = FALSE; + gboolean verified; + + meta_stack_op_dump (op, "Stack op event received: ", "\n"); + + if (op->any.serial < tracker->xserver_serial) + { + /* g_warning ("Spurious X event received affecting stack; doing full re-query"); */ + resync_verified_stack_with_xserver_stack (tracker); + meta_stack_tracker_dump (tracker); + return; + } + + tracker->xserver_serial = op->any.serial; + + /* XXX: With the design we have ended up with it looks like we've + * ended up making it unnecessary to maintain tracker->xserver_stack + * since we only need an xserver_stack during the + * resync_verified_stack_with_xserver_stack() at which point we are + * going to query the full stack from the X server using + * XQueryTree() anyway. + * + * TODO: remove tracker->xserver_stack. + */ + meta_stack_op_apply (op, tracker->xserver_stack); + + verified = stack_tracker_verify_predictions (tracker, op, &need_sync); + if (!verified) + { + resync_verified_stack_with_xserver_stack (tracker); + meta_stack_tracker_dump (tracker); + return; + } + meta_stack_tracker_dump (tracker); } @@ -565,7 +1079,8 @@ meta_stack_tracker_create_event (MetaStackTracker *tracker, op.any.type = STACK_OP_ADD; op.any.serial = event->serial; - op.add.window = event->window; + op.add.window.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.add.window.x11.xwindow = event->window; stack_tracker_event_received (tracker, &op); } @@ -578,7 +1093,8 @@ meta_stack_tracker_destroy_event (MetaStackTracker *tracker, op.any.type = STACK_OP_REMOVE; op.any.serial = event->serial; - op.remove.window = event->window; + op.remove.window.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.remove.window.x11.xwindow = event->window; stack_tracker_event_received (tracker, &op); } @@ -593,7 +1109,8 @@ meta_stack_tracker_reparent_event (MetaStackTracker *tracker, op.any.type = STACK_OP_ADD; op.any.serial = event->serial; - op.add.window = event->window; + op.add.window.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.add.window.x11.xwindow = event->window; stack_tracker_event_received (tracker, &op); } @@ -603,7 +1120,8 @@ meta_stack_tracker_reparent_event (MetaStackTracker *tracker, op.any.type = STACK_OP_REMOVE; op.any.serial = event->serial; - op.remove.window = event->window; + op.remove.window.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.remove.window.x11.xwindow = event->window; stack_tracker_event_received (tracker, &op); } @@ -617,8 +1135,10 @@ meta_stack_tracker_configure_event (MetaStackTracker *tracker, op.any.type = STACK_OP_RAISE_ABOVE; op.any.serial = event->serial; - op.raise_above.window = event->window; - op.raise_above.sibling = event->above; + op.raise_above.window.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.raise_above.window.x11.xwindow = event->window; + op.raise_above.sibling.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.raise_above.sibling.x11.xwindow = event->above; stack_tracker_event_received (tracker, &op); } @@ -642,14 +1162,14 @@ meta_stack_tracker_configure_event (MetaStackTracker *tracker, */ void meta_stack_tracker_get_stack (MetaStackTracker *tracker, - Window **windows, + MetaStackWindow **windows, int *n_windows) { GArray *stack; - if (tracker->queued_requests->length == 0) + if (tracker->unverified_predictions->length == 0) { - stack = tracker->server_stack; + stack = tracker->verified_stack; } else { @@ -657,9 +1177,8 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker, { GList *l; - tracker->predicted_stack = copy_stack ((Window *)tracker->server_stack->data, - tracker->server_stack->len); - for (l = tracker->queued_requests->head; l; l = l->next) + tracker->predicted_stack = copy_stack (tracker->verified_stack); + for (l = tracker->unverified_predictions->head; l; l = l->next) { MetaStackOp *op = l->data; meta_stack_op_apply (op, tracker->predicted_stack); @@ -669,8 +1188,11 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker, stack = tracker->predicted_stack; } + meta_topic (META_DEBUG_STACK, "Get Stack\n"); + meta_stack_tracker_dump (tracker); + if (windows) - *windows = (Window *)stack->data; + *windows = (MetaStackWindow *)stack->data; if (n_windows) *n_windows = stack->len; } @@ -685,8 +1207,8 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker, void meta_stack_tracker_sync_stack (MetaStackTracker *tracker) { + MetaStackWindow *windows; GList *meta_windows; - Window *windows; int n_windows; int i; @@ -701,26 +1223,30 @@ meta_stack_tracker_sync_stack (MetaStackTracker *tracker) meta_windows = NULL; for (i = 0; i < n_windows; i++) { - MetaWindow *meta_window; - - meta_window = meta_display_lookup_x_window (tracker->screen->display, - windows[i]); - /* When mapping back from xwindow to MetaWindow we have to be a bit careful; - * children of the root could include unmapped windows created by toolkits - * for internal purposes, including ones that we have registered in our - * XID => window table. (Wine uses a toplevel for _NET_WM_USER_TIME_WINDOW; - * see window-prop.c:reload_net_wm_user_time_window() for registration.) - */ - if (meta_window && - (windows[i] == meta_window->xwindow || - (meta_window->frame && windows[i] == meta_window->frame->xwindow))) - meta_windows = g_list_prepend (meta_windows, meta_window); - } - - if (tracker->screen->display->compositor) - meta_compositor_sync_stack (tracker->screen->display->compositor, - tracker->screen, - meta_windows); + MetaStackWindow *window = &windows[i]; + + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + MetaWindow *meta_window = + meta_display_lookup_x_window (tracker->screen->display, windows[i].x11.xwindow); + + /* When mapping back from xwindow to MetaWindow we have to be a bit careful; + * children of the root could include unmapped windows created by toolkits + * for internal purposes, including ones that we have registered in our + * XID => window table. (Wine uses a toplevel for _NET_WM_USER_TIME_WINDOW; + * see window-prop.c:reload_net_wm_user_time_window() for registration.) + */ + if (meta_window && + (windows[i].x11.xwindow == meta_window->xwindow || + (meta_window->frame && windows[i].x11.xwindow == meta_window->frame->xwindow))) + meta_windows = g_list_prepend (meta_windows, meta_window); + } + else + meta_windows = g_list_prepend (meta_windows, window->wayland.meta_window); + } + + meta_compositor_sync_stack (tracker->screen->display->compositor, + meta_windows); g_list_free (meta_windows); meta_screen_restacked (tracker->screen); diff --git a/src/core/stack-tracker.h b/src/core/stack-tracker.h index 36d5251..f74400e 100644 --- a/src/core/stack-tracker.h +++ b/src/core/stack-tracker.h @@ -35,36 +35,55 @@ #define META_STACK_TRACKER_H #include <meta/screen.h> +#include <meta/window.h> typedef struct _MetaStackTracker MetaStackTracker; +typedef union _MetaStackWindow +{ + struct { + MetaWindowClientType type; + } any; + struct { + MetaWindowClientType type; + Window xwindow; + } x11; + struct { + MetaWindowClientType type; + MetaWindow *meta_window; + } wayland; +} MetaStackWindow; + +gboolean meta_stack_window_equal (const MetaStackWindow *a, + const MetaStackWindow *b); + MetaStackTracker *meta_stack_tracker_new (MetaScreen *screen); void meta_stack_tracker_free (MetaStackTracker *tracker); /* These functions are called when we make an X call that changes the * stacking order; this allows MetaStackTracker to predict stacking * order before it receives events back from the X server */ -void meta_stack_tracker_record_add (MetaStackTracker *tracker, - Window window, - gulong serial); -void meta_stack_tracker_record_remove (MetaStackTracker *tracker, - Window window, - gulong serial); -void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, - Window *windows, - int n_windows, - gulong serial); -void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, - Window window, - Window sibling, - gulong serial); -void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker, - Window window, - Window sibling, - gulong serial); -void meta_stack_tracker_record_lower (MetaStackTracker *tracker, - Window window, - gulong serial); +void meta_stack_tracker_record_add (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial); +void meta_stack_tracker_record_remove (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial); +void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, + const MetaStackWindow *windows, + int n_windows, + gulong serial); +void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, + const MetaStackWindow *window, + const MetaStackWindow *sibling, + gulong serial); +void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker, + const MetaStackWindow *window, + const MetaStackWindow *sibling, + gulong serial); +void meta_stack_tracker_record_lower (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial); /* These functions are used to update the stack when we get events * reflecting changes to the stacking order */ @@ -77,9 +96,9 @@ void meta_stack_tracker_reparent_event (MetaStackTracker *tracker, void meta_stack_tracker_configure_event (MetaStackTracker *tracker, XConfigureEvent *event); -void meta_stack_tracker_get_stack (MetaStackTracker *tracker, - Window **windows, - int *n_windows); +void meta_stack_tracker_get_stack (MetaStackTracker *tracker, + MetaStackWindow **windows, + int *n_entries); void meta_stack_tracker_sync_stack (MetaStackTracker *tracker); void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker); diff --git a/src/core/stack.c b/src/core/stack.c index 18f1d7e..68400e2 100644 --- a/src/core/stack.c +++ b/src/core/stack.c @@ -36,6 +36,8 @@ #include <X11/Xatom.h> +#include "x11/group-private.h" + #define WINDOW_HAS_TRANSIENT_TYPE(w) \ (w->type == META_WINDOW_DIALOG || \ w->type == META_WINDOW_MODAL_DIALOG || \ @@ -50,7 +52,7 @@ #define WINDOW_IN_STACK(w) (w->stack_position >= 0) -static void stack_sync_to_server (MetaStack *stack); +static void stack_sync_to_xserver (MetaStack *stack); static void meta_window_set_stack_position_no_sync (MetaWindow *window, int position); static void stack_do_window_deletions (MetaStack *stack); @@ -69,14 +71,14 @@ meta_stack_new (MetaScreen *screen) stack = g_new (MetaStack, 1); stack->screen = screen; - stack->windows = g_array_new (FALSE, FALSE, sizeof (Window)); + stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window)); stack->sorted = NULL; stack->added = NULL; stack->removed = NULL; stack->freeze_count = 0; - stack->last_root_children_stacked = NULL; + stack->last_all_root_children_stacked = NULL; stack->n_positions = 0; @@ -87,17 +89,24 @@ meta_stack_new (MetaScreen *screen) return stack; } +static void +free_last_all_root_children_stacked_cache (MetaStack *stack) +{ + g_array_free (stack->last_all_root_children_stacked, TRUE); + stack->last_all_root_children_stacked = NULL; +} + void meta_stack_free (MetaStack *stack) { - g_array_free (stack->windows, TRUE); + g_array_free (stack->xwindows, TRUE); g_list_free (stack->sorted); g_list_free (stack->added); g_list_free (stack->removed); - if (stack->last_root_children_stacked) - g_array_free (stack->last_root_children_stacked, TRUE); + if (stack->last_all_root_children_stacked) + free_last_all_root_children_stacked_cache (stack); g_free (stack); } @@ -119,7 +128,7 @@ meta_stack_add (MetaStack *stack, "Window %s has stack_position initialized to %d\n", window->desc, window->stack_position); - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -155,7 +164,7 @@ meta_stack_remove (MetaStack *stack, stack->removed = g_list_prepend (stack->removed, GUINT_TO_POINTER (window->frame->xwindow)); - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -165,7 +174,7 @@ meta_stack_update_layer (MetaStack *stack, { stack->need_relayer = TRUE; - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -175,7 +184,7 @@ meta_stack_update_transient (MetaStack *stack, { stack->need_constrain = TRUE; - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -204,7 +213,7 @@ meta_stack_raise (MetaStack *stack, meta_window_set_stack_position_no_sync (window, max_stack_position); - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -232,7 +241,7 @@ meta_stack_lower (MetaStack *stack, meta_window_set_stack_position_no_sync (window, min_stack_position); - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -248,7 +257,7 @@ meta_stack_thaw (MetaStack *stack) g_return_if_fail (stack->freeze_count > 0); stack->freeze_count -= 1; - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, NULL); } @@ -827,7 +836,7 @@ stack_do_window_deletions (MetaStack *stack) /* We go from the end figuring removals are more * likely to be recent. */ - i = stack->windows->len; + i = stack->xwindows->len; while (i > 0) { --i; @@ -838,9 +847,9 @@ stack_do_window_deletions (MetaStack *stack) * both the window->xwindow and window->frame->xwindow * in the removal list. */ - if (xwindow == g_array_index (stack->windows, Window, i)) + if (xwindow == g_array_index (stack->xwindows, Window, i)) { - g_array_remove_index (stack->windows, i); + g_array_remove_index (stack->xwindows, i); goto next; } } @@ -869,10 +878,10 @@ stack_do_window_additions (MetaStack *stack) "Adding %d windows to sorted list\n", n_added); - old_size = stack->windows->len; - g_array_set_size (stack->windows, old_size + n_added); + old_size = stack->xwindows->len; + g_array_set_size (stack->xwindows, old_size + n_added); - end = &g_array_index (stack->windows, Window, old_size); + end = &g_array_index (stack->xwindows, Window, old_size); /* stack->added has the most recent additions at the * front of the list, so we need to reverse it @@ -1027,6 +1036,102 @@ stack_ensure_sorted (MetaStack *stack) stack_do_resort (stack); } +static MetaStackWindow * +find_top_most_managed_window (MetaScreen *screen, + const MetaStackWindow *ignore) +{ + MetaStackTracker *stack_tracker = screen->stack_tracker; + MetaStackWindow *windows; + int n_windows; + int i; + + meta_stack_tracker_get_stack (stack_tracker, + &windows, &n_windows); + + /* Children are in order from bottom to top. We want to + * find the topmost managed child, then configure + * our window to be above it. + */ + for (i = n_windows -1; i >= 0; i--) + { + MetaStackWindow *other_window = &windows[i]; + + if (other_window->any.type == ignore->any.type && + ((other_window->any.type == META_WINDOW_CLIENT_TYPE_X11 && + other_window->x11.xwindow == ignore->x11.xwindow) || + other_window->wayland.meta_window == ignore->wayland.meta_window)) + { + /* Do nothing. This means we're already the topmost managed + * window, but it DOES NOT mean we are already just above + * the topmost managed window. This is important because if + * an override redirect window is up, and we map a new + * managed window, the new window is probably above the old + * popup by default, and we want to push it below that + * popup. So keep looking for a sibling managed window + * to be moved below. + */ + } + else + { + if (other_window->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + MetaWindow *other = meta_display_lookup_x_window (screen->display, + other_window->x11.xwindow); + + if (other != NULL && !other->override_redirect) + return other_window; + } + else + { + /* All wayland windows are currently considered "managed" + * TODO: consider wayland pop-up windows like override + * redirect windows here. */ + return other_window; + } + } + } + + return NULL; +} + +/* When moving an X window we sometimes need an X based sibling. + * + * If the given sibling is X based this function returns it back + * otherwise it searches downwards looking for the nearest X window. + * + * If no X based sibling could be found return NULL. */ +static MetaStackWindow * +find_x11_sibling_downwards (MetaScreen *screen, + MetaStackWindow *sibling) +{ + MetaStackTracker *stack_tracker = screen->stack_tracker; + MetaStackWindow *windows; + int n_windows; + int i; + + if (sibling->any.type == META_WINDOW_CLIENT_TYPE_X11) + return sibling; + + meta_stack_tracker_get_stack (stack_tracker, + &windows, &n_windows); + + /* NB: Children are in order from bottom to top and we + * want to search downwards for the nearest X window. + */ + + for (i = n_windows - 1; i >= 0; i--) + if (meta_stack_window_equal (&windows[i], sibling)) + break; + + for (; i >= 0; i--) + { + if (windows[i].any.type == META_WINDOW_CLIENT_TYPE_X11) + return &windows[i]; + } + + return NULL; +} + /** * raise_window_relative_to_managed_windows: * @@ -1051,84 +1156,74 @@ stack_ensure_sorted (MetaStack *stack) */ static void raise_window_relative_to_managed_windows (MetaScreen *screen, - Window xwindow) + const MetaStackWindow *window) { + gulong serial = 0; + MetaStackWindow *sibling; - Window *children; - int n_children; - int i; - - meta_stack_tracker_get_stack (screen->stack_tracker, - &children, &n_children); - - /* Children are in order from bottom to top. We want to - * find the topmost managed child, then configure - * our window to be above it. - */ - i = n_children - 1; - while (i >= 0) + sibling = find_top_most_managed_window (screen, window); + if (!sibling) { - if (children[i] == xwindow) + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) { - /* Do nothing. This means we're already the topmost managed - * window, but it DOES NOT mean we are already just above - * the topmost managed window. This is important because if - * an override redirect window is up, and we map a new - * managed window, the new window is probably above the old - * popup by default, and we want to push it below that - * popup. So keep looking for a sibling managed window - * to be moved below. + serial = XNextRequest (screen->display->xdisplay); + meta_error_trap_push (screen->display); + XLowerWindow (screen->display->xdisplay, + window->x11.xwindow); + meta_error_trap_pop (screen->display); + } + + /* No sibling to use, just lower ourselves to the bottom + * to be sure we're below any override redirect windows. */ + meta_stack_tracker_record_lower (screen->stack_tracker, + window, + serial); + return; } - else - { - MetaWindow *other = meta_display_lookup_x_window (screen->display, - children[i]); - if (other != NULL && !other->override_redirect) - { - XWindowChanges changes; - /* children[i] is the topmost managed child */ + /* window is the topmost managed child */ meta_topic (META_DEBUG_STACK, "Moving 0x%lx above topmost managed child window 0x%lx\n", - xwindow, children[i]); + window->any.type == META_WINDOW_CLIENT_TYPE_X11 ? window->x11.xwindow: 0, + sibling->any.type == META_WINDOW_CLIENT_TYPE_X11 ? sibling->x11.xwindow: 0); - changes.sibling = children[i]; + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + XWindowChanges changes; + MetaStackWindow *x11_sibling = find_x11_sibling_downwards (screen, sibling); + serial = XNextRequest (screen->display->xdisplay); + + if (x11_sibling) + { + changes.sibling = x11_sibling->x11.xwindow; changes.stack_mode = Above; meta_error_trap_push (screen->display); - meta_stack_tracker_record_raise_above (screen->stack_tracker, - xwindow, - children[i], - XNextRequest (screen->display->xdisplay)); XConfigureWindow (screen->display->xdisplay, - xwindow, + window->x11.xwindow, CWSibling | CWStackMode, &changes); meta_error_trap_pop (screen->display); - - break; - } } - - --i; - } - - if (i < 0) + else { /* No sibling to use, just lower ourselves to the bottom * to be sure we're below any override redirect windows. */ meta_error_trap_push (screen->display); - meta_stack_tracker_record_lower (screen->stack_tracker, - xwindow, - XNextRequest (screen->display->xdisplay)); XLowerWindow (screen->display->xdisplay, - xwindow); + window->x11.xwindow); meta_error_trap_pop (screen->display); } } + meta_stack_tracker_record_raise_above (screen->stack_tracker, + window, + sibling, + serial); +} + /** * stack_sync_to_server: * @@ -1143,13 +1238,16 @@ raise_window_relative_to_managed_windows (MetaScreen *screen, * job of computing the minimal set of stacking requests needed. */ static void -stack_sync_to_server (MetaStack *stack) +stack_sync_to_xserver (MetaStack *stack) { - GArray *stacked; - GArray *root_children_stacked; + GArray *x11_stacked; + GArray *x11_root_children_stacked; + GArray *all_root_children_stacked; /* wayland OR x11 */ GList *tmp; - GArray *all_hidden; + GArray *x11_hidden; + GArray *x11_hidden_stack_windows; int n_override_redirect = 0; + MetaStackWindow guard_stack_window; /* Bail out if frozen */ if (stack->freeze_count > 0) @@ -1164,13 +1262,17 @@ stack_sync_to_server (MetaStack *stack) * _NET hints, and "root_children_stacked" is in top-to-bottom * order for XRestackWindows() */ - stacked = g_array_new (FALSE, FALSE, sizeof (Window)); - root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); - all_hidden = g_array_new (FALSE, FALSE, sizeof (Window)); + x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); + + all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow)); + x11_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); + + x11_hidden_stack_windows = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow)); + x11_hidden = g_array_new (FALSE, FALSE, sizeof (Window)); /* The screen guard window sits above all hidden windows and acts as * a barrier to input reaching these windows. */ - g_array_append_val (all_hidden, stack->screen->guard_window); + g_array_append_val (x11_hidden, stack->screen->guard_window); meta_topic (META_DEBUG_STACK, "Top to bottom: "); meta_push_no_msg_prefix (); @@ -1179,6 +1281,9 @@ stack_sync_to_server (MetaStack *stack) { MetaWindow *w = tmp->data; Window top_level_window; + MetaStackWindow stack_window; + + stack_window.any.type = w->client_type; meta_topic (META_DEBUG_STACK, "%u:%d - %s ", w->layer, w->stack_position, w->desc); @@ -1187,60 +1292,82 @@ stack_sync_to_server (MetaStack *stack) if (w->override_redirect) n_override_redirect++; else - g_array_prepend_val (stacked, w->xwindow); + g_array_prepend_val (x11_stacked, w->xwindow); if (w->frame) top_level_window = w->frame->xwindow; else top_level_window = w->xwindow; + if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) + stack_window.x11.xwindow = top_level_window; + else + stack_window.wayland.meta_window = w; + /* We don't restack hidden windows along with the rest, though they are * reflected in the _NET hints. Hidden windows all get pushed below * the screens fullscreen guard_window. */ if (w->hidden) { - g_array_append_val (all_hidden, top_level_window); + if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) + { + MetaStackWindow stack_window; + + stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_window.x11.xwindow = top_level_window; + + g_array_append_val (x11_hidden_stack_windows, stack_window); + g_array_append_val (x11_hidden, top_level_window); + } continue; } + g_array_append_val (all_root_children_stacked, stack_window); + /* build XRestackWindows() array from top to bottom */ - g_array_append_val (root_children_stacked, top_level_window); + if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) + g_array_append_val (x11_root_children_stacked, top_level_window); } meta_topic (META_DEBUG_STACK, "\n"); meta_pop_no_msg_prefix (); - /* All windows should be in some stacking order */ - if (stacked->len != stack->windows->len - n_override_redirect) + /* All X windows should be in some stacking order */ + if (x11_stacked->len != stack->xwindows->len - n_override_redirect) meta_bug ("%u windows stacked, %u windows exist in stack\n", - stacked->len, stack->windows->len); + x11_stacked->len, stack->xwindows->len); /* Sync to server */ meta_topic (META_DEBUG_STACK, "Restacking %u windows\n", - root_children_stacked->len); + all_root_children_stacked->len); meta_error_trap_push (stack->screen->display); - if (stack->last_root_children_stacked == NULL) + if (stack->last_all_root_children_stacked == NULL) { /* Just impose our stack, we don't know the previous state. * This involves a ton of circulate requests and may flicker. */ meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n"); - if (root_children_stacked->len > 0) + if (all_root_children_stacked->len > 1) { - meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, - (Window *) root_children_stacked->data, - root_children_stacked->len, - XNextRequest (stack->screen->display->xdisplay)); + gulong serial = 0; + if (x11_root_children_stacked->len > 1) + { + serial = XNextRequest (stack->screen->display->xdisplay); XRestackWindows (stack->screen->display->xdisplay, - (Window *) root_children_stacked->data, - root_children_stacked->len); + (Window *) x11_root_children_stacked->data, + x11_root_children_stacked->len); + } + meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, + (MetaStackWindow *) all_root_children_stacked->data, + all_root_children_stacked->len, + serial); } } - else if (root_children_stacked->len > 0) + else if (all_root_children_stacked->len > 0) { /* Try to do minimal window moves to get the stack in order */ /* A point of note: these arrays include frames not client windows, @@ -1248,28 +1375,34 @@ stack_sync_to_server (MetaStack *stack) * was saved, then we may have inefficiency, but I don't think things * break... */ - const Window *old_stack = (Window *) stack->last_root_children_stacked->data; - const Window *new_stack = (Window *) root_children_stacked->data; - const int old_len = stack->last_root_children_stacked->len; - const int new_len = root_children_stacked->len; - const Window *oldp = old_stack; - const Window *newp = new_stack; - const Window *old_end = old_stack + old_len; - const Window *new_end = new_stack + new_len; - Window last_window = None; - + const MetaStackWindow *old_stack = (MetaStackWindow *) stack->last_all_root_children_stacked->data; + const MetaStackWindow *new_stack = (MetaStackWindow *) all_root_children_stacked->data; + const int old_len = stack->last_all_root_children_stacked->len; + const int new_len = all_root_children_stacked->len; + const MetaStackWindow *oldp = old_stack; + const MetaStackWindow *newp = new_stack; + const MetaStackWindow *old_end = old_stack + old_len; + const MetaStackWindow *new_end = new_stack + new_len; + Window last_xwindow = None; + const MetaStackWindow *last_window = NULL; + while (oldp != old_end && newp != new_end) { - if (*oldp == *newp) + if (meta_stack_window_equal (oldp, newp)) { /* Stacks are the same here, move on */ ++oldp; - last_window = *newp; + if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11) + last_xwindow = newp->x11.xwindow; + last_window = newp; ++newp; } - else if (meta_display_lookup_x_window (stack->screen->display, - *oldp) == NULL) + else if ((oldp->any.type == META_WINDOW_CLIENT_TYPE_X11 && + meta_display_lookup_x_window (stack->screen->display, + oldp->x11.xwindow) == NULL) || + (oldp->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND && + oldp->wayland.meta_window == NULL)) { /* *oldp is no longer known to us (probably destroyed), * so we can just skip it @@ -1278,75 +1411,161 @@ stack_sync_to_server (MetaStack *stack) } else { - /* Move *newp below last_window */ - if (last_window == None) + /* Move *newp below the last_window */ + if (!last_window) + { + meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", + newp->x11.xwindow); + + raise_window_relative_to_managed_windows (stack->screen, newp); + } + else if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11 && + last_xwindow == None) { - meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp); + /* In this case we have an X window that we need to + * put below a wayland window and this is the + * topmost X window. */ + + /* In X terms (because this is the topmost X window) + * we want to + * raise_window_relative_to_managed_windows() to + * ensure the X window is below override-redirect + * pop-up windows. + * + * In Wayland terms we just want to ensure + * newp is lowered below last_window (which + * notably doesn't require an X request because we + * know last_window isn't an X window). + */ + + raise_window_relative_to_managed_windows (stack->screen, newp); - raise_window_relative_to_managed_windows (stack->screen, - *newp); + meta_stack_tracker_record_lower_below (stack->screen->stack_tracker, + newp, last_window, + 0); /* no x request serial */ } else { - /* This means that if last_window is dead, but not + gulong serial = 0; + + /* This means that if last_xwindow is dead, but not * *newp, then we fail to restack *newp; but on - * unmanaging last_window, we'll fix it up. + * unmanaging last_xwindow, we'll fix it up. */ + meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n", + newp->any.type == META_WINDOW_CLIENT_TYPE_X11 ? newp->x11.xwindow : 0, + last_xwindow); + + if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11) + { XWindowChanges changes; + serial = XNextRequest (stack->screen->display->xdisplay); - changes.sibling = last_window; + changes.sibling = last_xwindow; changes.stack_mode = Below; - meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n", - *newp, last_window); - - meta_stack_tracker_record_lower_below (stack->screen->stack_tracker, - *newp, last_window, - XNextRequest (stack->screen->display->xdisplay)); XConfigureWindow (stack->screen->display->xdisplay, - *newp, + newp->x11.xwindow, CWSibling | CWStackMode, &changes); } - last_window = *newp; + meta_stack_tracker_record_lower_below (stack->screen->stack_tracker, + newp, last_window, + serial); + } + + if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11) + last_xwindow = newp->x11.xwindow; + last_window = newp; ++newp; } } if (newp != new_end) { + const MetaStackWindow *x_ref; + unsigned long serial = 0; + /* Restack remaining windows */ meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n", (int) (new_end - newp)); + + /* rewind until we find the last stacked X window that we can use + * as a reference point for re-stacking remaining X windows */ + if (newp != new_stack) + for (x_ref = newp - 1; + x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack; + x_ref--) + ; + else + x_ref = new_stack; + + /* If we didn't find an X window looking backwards then walk forwards + * through the remaining windows to find the first remaining X window + * instead. */ + if (x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11) + { + for (x_ref = newp; + x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack; + x_ref++) + ; + } + + /* If there are any X windows remaining unstacked then restack them */ + if (x_ref->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + int i; + + for (i = x11_root_children_stacked->len - 1; i; i--) + { + Window *reference = &g_array_index (x11_root_children_stacked, Window, i); + + if (*reference == x_ref->x11.xwindow) + { + int n = x11_root_children_stacked->len - i; + + /* There's no point restacking if there's only one X window */ + if (n == 1) + break; + + serial = XNextRequest (stack->screen->display->xdisplay); + XRestackWindows (stack->screen->display->xdisplay, + reference, n); + break; + } + } + } + /* We need to include an already-stacked window * in the restack call, so we get in the proper position * with respect to it. */ if (newp != new_stack) - --newp; + newp = MIN (newp - 1, x_ref); meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, - (Window *) newp, new_end - newp, - XNextRequest (stack->screen->display->xdisplay)); - XRestackWindows (stack->screen->display->xdisplay, - (Window *) newp, new_end - newp); + newp, new_end - newp, + serial); } } - /* Push hidden windows to the bottom of the stack under the guard window */ + /* Push hidden X windows to the bottom of the stack under the guard window */ + guard_stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + guard_stack_window.x11.xwindow = stack->screen->guard_window; meta_stack_tracker_record_lower (stack->screen->stack_tracker, - stack->screen->guard_window, + &guard_stack_window, XNextRequest (stack->screen->display->xdisplay)); XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window); meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, - (Window *)all_hidden->data, - all_hidden->len, + (MetaStackWindow *)x11_hidden_stack_windows->data, + x11_hidden_stack_windows->len, XNextRequest (stack->screen->display->xdisplay)); XRestackWindows (stack->screen->display->xdisplay, - (Window *)all_hidden->data, - all_hidden->len); - g_array_free (all_hidden, TRUE); + (Window *)x11_hidden->data, + x11_hidden->len); + g_array_free (x11_hidden, TRUE); + g_array_free (x11_hidden_stack_windows, TRUE); meta_error_trap_pop (stack->screen->display); /* on error, a window was destroyed; it should eventually @@ -1361,21 +1580,23 @@ stack_sync_to_server (MetaStack *stack) stack->screen->display->atom__NET_CLIENT_LIST, XA_WINDOW, 32, PropModeReplace, - (unsigned char *)stack->windows->data, - stack->windows->len); + (unsigned char *)stack->xwindows->data, + stack->xwindows->len); XChangeProperty (stack->screen->display->xdisplay, stack->screen->xroot, stack->screen->display->atom__NET_CLIENT_LIST_STACKING, XA_WINDOW, 32, PropModeReplace, - (unsigned char *)stacked->data, - stacked->len); + (unsigned char *)x11_stacked->data, + x11_stacked->len); + + g_array_free (x11_stacked, TRUE); - g_array_free (stacked, TRUE); + if (stack->last_all_root_children_stacked) + free_last_all_root_children_stacked_cache (stack); + stack->last_all_root_children_stacked = all_root_children_stacked; - if (stack->last_root_children_stacked) - g_array_free (stack->last_root_children_stacked, TRUE); - stack->last_root_children_stacked = root_children_stacked; + g_array_free (x11_root_children_stacked, TRUE); /* That was scary... */ } @@ -1486,8 +1707,8 @@ get_default_focus_window (MetaStack *stack, MetaWindow *topmost_in_group; MetaWindow *topmost_overall; MetaGroup *not_this_one_group; - GList *link; - + GList *l; + transient_parent = NULL; topmost_in_group = NULL; topmost_overall = NULL; @@ -1499,49 +1720,49 @@ get_default_focus_window (MetaStack *stack, stack_ensure_sorted (stack); /* top of this layer is at the front of the list */ - link = stack->sorted; - - while (link) + for (l = stack->sorted; l != NULL; l = l->next) { - MetaWindow *window = link->data; + MetaWindow *window = l->data; - if (window && - window != not_this_one && - (window->unmaps_pending == 0) && - !window->minimized && - (window->input || window->take_focus) && - (workspace == NULL || - meta_window_located_on_workspace (window, workspace))) - { - if (not_this_one != NULL) - { - if (transient_parent == NULL && - not_this_one->xtransient_for != None && - not_this_one->xtransient_for == window->xwindow && - (!must_be_at_point || - window_contains_point (window, root_x, root_y))) - transient_parent = window; - - if (topmost_in_group == NULL && - not_this_one_group != NULL && - not_this_one_group == meta_window_get_group (window) && - (!must_be_at_point || - window_contains_point (window, root_x, root_y))) - topmost_in_group = window; - } + if (!window) + continue; - if (topmost_overall == NULL && - window->type != META_WINDOW_DOCK && - (!must_be_at_point || - window_contains_point (window, root_x, root_y))) - topmost_overall = window; + if (window == not_this_one) + continue; - /* We could try to bail out early here for efficiency in - * some cases, but it's just not worth the code. - */ + if (window->unmaps_pending > 0) + continue; + + if (window->minimized) + continue; + + if (!(window->input || window->take_focus)) + continue; + + if (workspace != NULL && !meta_window_located_on_workspace (window, workspace)) + continue; + + if (must_be_at_point && !window_contains_point (window, root_x, root_y)) + continue; + + if (not_this_one != NULL) + { + if (transient_parent == NULL && + meta_window_get_transient_for (not_this_one) == window) + transient_parent = window; + + if (topmost_in_group == NULL && + not_this_one_group != NULL && + not_this_one_group == meta_window_get_group (window)) + topmost_in_group = window; } - link = link->next; + if (topmost_overall == NULL && window->type != META_WINDOW_DOCK) + topmost_overall = window; + + /* We could try to bail out early here for efficiency in + * some cases, but it's just not worth the code. + */ } if (transient_parent) @@ -1726,7 +1947,7 @@ meta_stack_set_positions (MetaStack *stack, meta_topic (META_DEBUG_STACK, "Reset the stack positions of (nearly) all windows\n"); - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, NULL); } @@ -1789,7 +2010,7 @@ meta_window_set_stack_position (MetaWindow *window, int position) { meta_window_set_stack_position_no_sync (window, position); - stack_sync_to_server (window->screen->stack); + stack_sync_to_xserver (window->screen->stack); meta_stack_update_window_tile_matches (window->screen->stack, window->screen->active_workspace); } diff --git a/src/core/stack.h b/src/core/stack.h index b0cd1ba..f9555a9 100644 --- a/src/core/stack.h +++ b/src/core/stack.h @@ -58,7 +58,7 @@ struct _MetaStack * A sequence of all the Windows (X handles, not MetaWindows) of the windows * we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST. */ - GArray *windows; + GArray *xwindows; /** The MetaWindows of the windows we manage, sorted in order. */ GList *sorted; @@ -97,7 +97,7 @@ struct _MetaStack * The last-known stack of all windows, bottom to top. We cache it here * so that subsequent times we'll be able to do incremental moves. */ - GArray *last_root_children_stacked; + GArray *last_all_root_children_stacked; /** * Number of stack positions; same as the length of added, but diff --git a/src/core/util-private.h b/src/core/util-private.h index 8e51b42..6f25806 100644 --- a/src/core/util-private.h +++ b/src/core/util-private.h @@ -32,5 +32,6 @@ void meta_set_verbose (gboolean setting); void meta_set_debugging (gboolean setting); void meta_set_syncing (gboolean setting); void meta_set_replace_current_wm (gboolean setting); +void meta_set_is_wayland_compositor (gboolean setting); #endif diff --git a/src/core/util.c b/src/core/util.c index cde58ee..3ac907f 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -53,6 +53,7 @@ static gint verbose_topics = 0; static gboolean is_debugging = FALSE; static gboolean replace_current = FALSE; static int no_prefix = 0; +static gboolean is_wayland_compositor = FALSE; #ifdef WITH_VERBOSE_MODE static FILE* logfile = NULL; @@ -79,7 +80,7 @@ ensure_logfile (void) if (err != NULL) { - meta_warning (_("Failed to open debug log: %s\n"), + meta_warning ("Failed to open debug log: %s\n", err->message); g_error_free (err); return; @@ -89,13 +90,13 @@ ensure_logfile (void) if (logfile == NULL) { - meta_warning (_("Failed to fdopen() log file %s: %s\n"), + meta_warning ("Failed to fdopen() log file %s: %s\n", filename, strerror (errno)); close (fd); } else { - g_printerr (_("Opened log file %s\n"), filename); + g_printerr ("Opened log file %s\n", filename); } g_free (filename); @@ -192,6 +193,18 @@ meta_set_replace_current_wm (gboolean setting) replace_current = setting; } +gboolean +meta_is_wayland_compositor (void) +{ + return is_wayland_compositor; +} + +void +meta_set_is_wayland_compositor (gboolean value) +{ + is_wayland_compositor = value; +} + char * meta_g_utf8_strndup (const gchar *src, gsize n) @@ -259,7 +272,7 @@ meta_debug_spew_real (const char *format, ...) out = logfile ? logfile : stderr; if (no_prefix == 0) - utf8_fputs (_("Window manager: "), out); + utf8_fputs ("Window manager: ", out); utf8_fputs (str, out); fflush (out); @@ -409,7 +422,7 @@ meta_bug (const char *format, ...) #endif if (no_prefix == 0) - utf8_fputs (_("Bug in window manager: "), out); + utf8_fputs ("Bug in window manager: ", out); utf8_fputs (str, out); fflush (out); @@ -440,7 +453,7 @@ meta_warning (const char *format, ...) #endif if (no_prefix == 0) - utf8_fputs (_("Window manager warning: "), out); + utf8_fputs ("Window manager warning: ", out); utf8_fputs (str, out); fflush (out); @@ -468,7 +481,7 @@ meta_fatal (const char *format, ...) #endif if (no_prefix == 0) - utf8_fputs (_("Window manager error: "), out); + utf8_fputs ("Window manager error: ", out); utf8_fputs (str, out); fflush (out); diff --git a/src/core/window-private.h b/src/core/window-private.h index fbeacab..374bca7 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -38,10 +38,15 @@ #include "screen-private.h" #include <meta/util.h> #include "stack.h" -#include "iconcache.h" #include <X11/Xutil.h> #include <cairo.h> #include <gdk-pixbuf/gdk-pixbuf.h> +#include <clutter/clutter.h> + +#include "x11/iconcache.h" +#include "x11/group-private.h" + +#include "wayland/meta-wayland-types.h" typedef struct _MetaWindowQueue MetaWindowQueue; @@ -60,13 +65,29 @@ typedef enum { #define NUMBER_OF_QUEUES 3 - typedef enum { _NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0, _NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1, _NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2, } MetaBypassCompositorHintValue; +typedef enum +{ + META_IS_CONFIGURE_REQUEST = 1 << 0, + META_DO_GRAVITY_ADJUST = 1 << 1, + META_IS_USER_ACTION = 1 << 2, + META_IS_MOVE_ACTION = 1 << 3, + META_IS_RESIZE_ACTION = 1 << 4, + META_IS_WAYLAND_RESIZE = 1 << 5 +} MetaMoveResizeFlags; + +typedef enum +{ + META_MOVE_RESIZE_RESULT_MOVED = 1 << 0, + META_MOVE_RESIZE_RESULT_RESIZED = 1 << 1, + META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED = 1 << 2, +} MetaMoveResizeResultFlags; + struct _MetaWindow { GObject parent_instance; @@ -75,25 +96,24 @@ struct _MetaWindow MetaScreen *screen; const MetaMonitorInfo *monitor; MetaWorkspace *workspace; + MetaWindowClientType client_type; + MetaWaylandSurface *surface; Window xwindow; /* may be NULL! not all windows get decorated */ MetaFrame *frame; int depth; Visual *xvisual; - Colormap colormap; char *desc; /* used in debug spew */ char *title; - char *icon_name; GdkPixbuf *icon; GdkPixbuf *mini_icon; MetaIconCache icon_cache; Pixmap wm_hints_pixmap; Pixmap wm_hints_mask; - + MetaWindowType type; - Atom type_atom; - + /* NOTE these five are not in UTF-8, we just treat them as random * binary data */ @@ -119,6 +139,7 @@ struct _MetaWindow Window xtransient_for; Window xgroup_leader; Window xclient_leader; + MetaWindow *transient_for; /* Initial workspace property */ int initial_workspace; @@ -153,8 +174,8 @@ struct _MetaWindow /* Whether we're fullscreen */ guint fullscreen : 1; - /* Whether the urgent flag of WM_HINTS is set */ - guint wm_hints_urgent : 1; + /* Whether the window is marked as urgent */ + guint urgent : 1; /* Whether we have to fullscreen after placement */ guint fullscreen_after_placement : 1; @@ -199,10 +220,18 @@ struct _MetaWindow */ guint hidden : 1; - /* Whether the compositor thinks the window is visible + /* Whether the compositor thinks the window is visible. + * This should match up with calls to meta_compositor_show_window / + * meta_compositor_hide_window. */ guint visible_to_compositor : 1; + /* Whether the compositor knows about the window. + * This should match up with calls to meta_compositor_add_window / + * meta_compositor_remove_window. + */ + guint known_to_compositor : 1; + /* When we next show or hide the window, what effect we should * tell the compositor to perform. */ @@ -232,7 +261,7 @@ struct _MetaWindow /* These are the flags from WM_PROTOCOLS */ guint take_focus : 1; guint delete_window : 1; - guint net_wm_ping : 1; + guint can_ping : 1; /* Globally active / No input */ guint input : 1; @@ -256,13 +285,6 @@ struct _MetaWindow guint has_move_func : 1; guint has_resize_func : 1; guint has_fullscreen_func : 1; - - /* Weird "_NET_WM_STATE_MODAL" flag */ - guint wm_state_modal : 1; - - /* TRUE if the client forced these on */ - guint wm_state_skip_taskbar : 1; - guint wm_state_skip_pager : 1; /* Computed whether to skip taskbar or not */ guint skip_taskbar : 1; @@ -316,15 +338,6 @@ struct _MetaWindow /* Transient parent is a root window */ guint transient_parent_is_root_window : 1; - - /* Info on which props we got our attributes from */ - guint using_net_wm_name : 1; /* vs. plain wm_name */ - guint using_net_wm_visible_name : 1; /* tracked so we can clear it */ - guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */ - guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */ - - /* icon props have changed */ - guint need_reread_icon : 1; /* if TRUE, window was maximized at start of current grab op */ guint shaken_loose : 1; @@ -341,6 +354,10 @@ struct _MetaWindow /* whether or not the window is from a program running on another machine */ guint is_remote : 1; + /* Used for Wayland -- surfaces can behave as if they were unmapped if + * they have a NULL buffer attached... */ + guint surface_mapped; + /* if non-NULL, the bounds of the window frame */ cairo_region_t *frame_bounds; @@ -398,6 +415,12 @@ struct _MetaWindow */ MetaRectangle rect; + /* The size and position we want the window to be (i.e. what we last asked + * the client to configure). + * This is only used for wayland clients. + */ + MetaRectangle expected_rect; + gboolean has_custom_frame_extents; GtkBorder custom_frame_extents; @@ -415,8 +438,6 @@ struct _MetaWindow * gives the position and size of the client window (i.e. ignoring * the frame). * - * Position valid if user_has_moved, size valid if user_has_resized - * * Position always in root coords, unlike window->rect. */ MetaRectangle user_rect; @@ -455,10 +476,24 @@ struct _MetaWindowClass { GObjectClass parent_class; - void (*workspace_changed) (MetaWindow *window, int old_workspace); - void (*focus) (MetaWindow *window); - void (*raised) (MetaWindow *window); - void (*unmanaged) (MetaWindow *window); + void (*manage) (MetaWindow *window); + void (*unmanage) (MetaWindow *window); + void (*ping) (MetaWindow *window, + guint32 serial); + void (*delete) (MetaWindow *window, + guint32 timestamp); + void (*kill) (MetaWindow *window); + void (*focus) (MetaWindow *window, + guint32 timestamp); + void (*move_resize_internal) (MetaWindow *window, + int gravity, + MetaRectangle requested_rect, + MetaRectangle constrained_rect, + MetaMoveResizeFlags flags, + MetaMoveResizeResultFlags *result); + void (*get_default_skip_hints) (MetaWindow *window, + gboolean *skip_taskbar_out, + gboolean *skip_pager_out); }; /* These differ from window->has_foo_func in that they consider @@ -486,10 +521,22 @@ struct _MetaWindowClass #define META_WINDOW_ALLOWS_HORIZONTAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && (w)->size_hints.min_width < (w)->size_hints.max_width) #define META_WINDOW_ALLOWS_VERTICAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && (w)->size_hints.min_height < (w)->size_hints.max_height) -MetaWindow* meta_window_new (MetaDisplay *display, - Window xwindow, - gboolean must_be_viewable, - MetaCompEffect effect); +MetaWindow * _meta_window_shared_new (MetaDisplay *display, + MetaScreen *screen, + MetaWindowClientType client_type, + MetaWaylandSurface *surface, + Window xwindow, + gulong existing_wm_state, + MetaCompEffect effect, + XWindowAttributes *attrs); + +MetaWindow * meta_window_x11_new (MetaDisplay *display, + Window xwindow, + gboolean must_be_viewable, + MetaCompEffect effect); +MetaWindow * meta_window_wayland_new (MetaDisplay *display, + MetaWaylandSurface *surface); + void meta_window_unmanage (MetaWindow *window, guint32 timestamp); void meta_window_calc_showing (MetaWindow *window); @@ -539,9 +586,6 @@ void meta_window_change_workspace (MetaWindow *window, /* Return whether the window should be currently mapped */ gboolean meta_window_should_be_showing (MetaWindow *window); -/* See warning in window.c about this function */ -gboolean __window_is_terminal (MetaWindow *window); - void meta_window_update_struts (MetaWindow *window); /* this gets root coords */ @@ -575,12 +619,6 @@ void meta_window_get_geometry (MetaWindow *window, void meta_window_update_unfocused_button_grabs (MetaWindow *window); -/* Sends a client message */ -void meta_window_send_icccm_message (MetaWindow *window, - Atom atom, - guint32 timestamp); - - void meta_window_move_resize_request(MetaWindow *window, guint value_mask, int gravity, @@ -588,12 +626,11 @@ void meta_window_move_resize_request(MetaWindow *window, int y, int width, int height); -gboolean meta_window_configure_request (MetaWindow *window, - XEvent *event); -gboolean meta_window_property_notify (MetaWindow *window, - XEvent *event); -gboolean meta_window_client_message (MetaWindow *window, - XEvent *event); +void meta_window_move_resize_wayland (MetaWindow *window, + int width, + int height, + int dx, + int dy); void meta_window_set_focused_internal (MetaWindow *window, gboolean focused); @@ -607,16 +644,15 @@ void meta_window_show_menu (MetaWindow *window, int button, guint32 timestamp); -void meta_window_set_gravity (MetaWindow *window, - int gravity); - #ifdef HAVE_XSYNC void meta_window_update_sync_request_counter (MetaWindow *window, gint64 new_counter_value); #endif /* HAVE_XSYNC */ -void meta_window_handle_mouse_grab_op_event (MetaWindow *window, - XIDeviceEvent *xev); +void meta_window_handle_mouse_grab_op_event (MetaWindow *window, + const ClutterEvent *event); +void meta_window_handle_mouse_grab_op_xevent (MetaWindow *window, + XIDeviceEvent *xevent); GList* meta_window_get_workspaces (MetaWindow *window); @@ -652,7 +688,8 @@ void meta_window_update_layer (MetaWindow *window); void meta_window_recalc_features (MetaWindow *window); -void meta_window_recalc_window_type (MetaWindow *window); +void meta_window_set_type (MetaWindow *window, + MetaWindowType type); void meta_window_frame_size_changed (MetaWindow *window); @@ -664,8 +701,6 @@ void meta_window_set_user_time (MetaWindow *window, void meta_window_update_icon_now (MetaWindow *window); -void meta_window_update_role (MetaWindow *window); -void meta_window_update_net_wm_type (MetaWindow *window); void meta_window_update_for_monitors_changed (MetaWindow *window); void meta_window_update_on_all_workspaces (MetaWindow *window); @@ -679,18 +714,56 @@ void meta_window_compute_tile_match (MetaWindow *window); gboolean meta_window_updates_are_frozen (MetaWindow *window); -void meta_window_update_opaque_region_x11 (MetaWindow *window); -void meta_window_update_input_region_x11 (MetaWindow *window); -void meta_window_update_shape_region_x11 (MetaWindow *window); +void meta_window_set_title (MetaWindow *window, + const char *title); +void meta_window_set_wm_class (MetaWindow *window, + const char *wm_class, + const char *wm_instance); +void meta_window_set_gtk_dbus_properties (MetaWindow *window, + const char *application_id, + const char *unique_bus_name, + const char *appmenu_path, + const char *menubar_path, + const char *application_object_path, + const char *window_object_path); + +void meta_window_set_transient_for (MetaWindow *window, + MetaWindow *parent); void meta_window_set_opacity (MetaWindow *window, guint opacity); +void meta_window_set_custom_frame_extents (MetaWindow *window, + GtkBorder *extents); + +void meta_window_handle_enter (MetaWindow *window, + guint32 timestamp, + guint root_x, + guint root_y); + +void meta_window_set_surface_mapped (MetaWindow *window, + gboolean surface_mapped); + Window meta_window_get_toplevel_xwindow (MetaWindow *window); void meta_window_get_client_area_rect (const MetaWindow *window, cairo_rectangle_int_t *rect); +void meta_window_activate_full (MetaWindow *window, + guint32 timestamp, + MetaClientType source_indication, + MetaWorkspace *workspace); + gboolean meta_window_is_client_decorated (MetaWindow *window); +void meta_window_update_monitor (MetaWindow *window); + +void meta_window_set_urgent (MetaWindow *window, + gboolean urgent); + +void meta_window_update_resize (MetaWindow *window, + gboolean snap, + int x, int y, + gboolean force); + #endif diff --git a/src/core/window.c b/src/core/window.c index 8fca023..5729d57 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -38,18 +38,14 @@ #include "keybindings-private.h" #include "ui.h" #include "place.h" -#include "session.h" #include <meta/prefs.h> -#include "resizepopup.h" -#include "xprops.h" #include <meta/group.h> -#include "window-props.h" +#include "resizepopup.h" #include "constraints.h" #include "mutter-enum-types.h" #include "core.h" #include <X11/Xatom.h> -#include <X11/Xlibint.h> /* For display->resource_mask */ #include <stdlib.h> #include <string.h> #include <math.h> @@ -58,7 +54,15 @@ #include <X11/extensions/shape.h> #endif -#include <X11/extensions/Xcomposite.h> +#include "meta/compositor-mutter.h" + +#include "x11/window-x11.h" +#include "x11/window-props.h" +#include "x11/xprops.h" +#include "x11/session.h" + +#include "wayland/window-wayland.h" +#include "wayland/meta-wayland-private.h" /* Windows that unmaximize to a size bigger than that fraction of the workarea * will be scaled down to that size (while maintaining aspect ratio). @@ -69,31 +73,17 @@ static int destroying_windows_disallowed = 0; -static void update_sm_hints (MetaWindow *window); -static void update_net_frame_extents (MetaWindow *window); -static void recalc_window_type (MetaWindow *window); -static void recalc_window_features (MetaWindow *window); static void invalidate_work_areas (MetaWindow *window); -static void set_wm_state_on_xwindow (MetaDisplay *display, - Window xwindow, - int state); static void set_wm_state (MetaWindow *window); static void set_net_wm_state (MetaWindow *window); static void meta_window_set_above (MetaWindow *window, gboolean new_value); -static void send_configure_notify (MetaWindow *window); -static gboolean process_property_notify (MetaWindow *window, - XPropertyEvent *event); - static void meta_window_force_placement (MetaWindow *window); static void meta_window_show (MetaWindow *window); static void meta_window_hide (MetaWindow *window); -static gboolean meta_window_same_client (MetaWindow *window, - MetaWindow *other_window); - static void meta_window_save_rect (MetaWindow *window); static void save_user_window_placement (MetaWindow *window); static void force_save_user_window_placement (MetaWindow *window); @@ -141,8 +131,6 @@ static void meta_window_move_between_rects (MetaWindow *window, static void unmaximize_window_before_freeing (MetaWindow *window); static void unminimize_window_and_all_transient_parents (MetaWindow *window); -static void meta_window_update_monitor (MetaWindow *window); - /* Idle handlers for the three queues (run with meta_later_add()). The * "data" parameter in each case will be a GINT_TO_POINTER of the * index into the queue arrays to use. @@ -154,7 +142,7 @@ static gboolean idle_calc_showing (gpointer data); static gboolean idle_move_resize (gpointer data); static gboolean idle_update_icon (gpointer data); -G_DEFINE_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT); +G_DEFINE_ABSTRACT_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT); enum { PROP_0, @@ -214,12 +202,21 @@ prefs_changed_callback (MetaPreference pref, window->type == META_WINDOW_MODAL_DIALOG) { window->attached = meta_window_should_attach_to_parent (window); - recalc_window_features (window); + meta_window_recalc_features (window); meta_window_queue (window, META_QUEUE_MOVE_RESIZE); } } static void +meta_window_real_get_default_skip_hints (MetaWindow *window, + gboolean *skip_taskbar_out, + gboolean *skip_pager_out) +{ + *skip_taskbar_out = FALSE; + *skip_pager_out = FALSE; +} + +static void meta_window_finalize (GObject *object) { MetaWindow *window = META_WINDOW (object); @@ -239,6 +236,9 @@ meta_window_finalize (GObject *object) if (window->opaque_region) cairo_region_destroy (window->opaque_region); + if (window->transient_for) + g_object_unref (window->transient_for); + meta_icon_cache_free (&window->icon_cache); g_free (window->sm_client_id); @@ -248,7 +248,6 @@ meta_window_finalize (GObject *object) g_free (window->res_class); g_free (window->res_name); g_free (window->title); - g_free (window->icon_name); g_free (window->desc); g_free (window->gtk_theme_variant); g_free (window->gtk_application_id); @@ -305,7 +304,7 @@ meta_window_get_property(GObject *object, g_value_set_boolean (value, win->wm_state_demands_attention); break; case PROP_URGENT: - g_value_set_boolean (value, win->wm_hints_urgent); + g_value_set_boolean (value, win->urgent); break; case PROP_SKIP_TASKBAR: g_value_set_boolean (value, win->skip_taskbar); @@ -373,6 +372,8 @@ meta_window_class_init (MetaWindowClass *klass) object_class->get_property = meta_window_get_property; object_class->set_property = meta_window_set_property; + klass->get_default_skip_hints = meta_window_real_get_default_skip_hints; + g_object_class_install_property (object_class, PROP_TITLE, g_param_spec_string ("title", @@ -569,7 +570,7 @@ meta_window_class_init (MetaWindowClass *klass) g_signal_new ("workspace-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MetaWindowClass, workspace_changed), + 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); @@ -578,7 +579,7 @@ meta_window_class_init (MetaWindowClass *klass) g_signal_new ("focus", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MetaWindowClass, focus), + 0, NULL, NULL, NULL, G_TYPE_NONE, 0); @@ -586,7 +587,7 @@ meta_window_class_init (MetaWindowClass *klass) g_signal_new ("raised", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MetaWindowClass, raised), + 0, NULL, NULL, NULL, G_TYPE_NONE, 0); @@ -594,7 +595,7 @@ meta_window_class_init (MetaWindowClass *klass) g_signal_new ("unmanaged", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MetaWindowClass, unmanaged), + 0, NULL, NULL, NULL, G_TYPE_NONE, 0); @@ -639,24 +640,6 @@ meta_window_init (MetaWindow *self) meta_prefs_add_listener (prefs_changed_callback, self); } -#ifdef WITH_VERBOSE_MODE -static const char* -wm_state_to_string (int state) -{ - switch (state) - { - case NormalState: - return "NormalState"; - case IconicState: - return "IconicState"; - case WithdrawnState: - return "WithdrawnState"; - } - - return "Unknown"; -} -#endif - static gboolean is_desktop_or_dock_foreach (MetaWindow *window, void *data) @@ -703,90 +686,6 @@ maybe_leave_show_desktop_mode (MetaWindow *window) } } -/* The MUTTER_WM_CLASS_FILTER environment variable is designed for - * performance and regression testing environments where we want to do - * tests with only a limited set of windows and ignore all other windows - * - * When it is set to a comma separated list of WM_CLASS class names, all - * windows not matching the list will be ignored. - * - * Returns TRUE if window has been filtered out and should be ignored. - */ -static gboolean -maybe_filter_window (MetaDisplay *display, - Window xwindow, - gboolean must_be_viewable, - XWindowAttributes *attrs) -{ - static char **filter_wm_classes = NULL; - static gboolean initialized = FALSE; - XClassHint class_hint; - gboolean filtered; - Status success; - int i; - - if (!initialized) - { - const char *filter_string = g_getenv ("MUTTER_WM_CLASS_FILTER"); - if (filter_string) - filter_wm_classes = g_strsplit (filter_string, ",", -1); - initialized = TRUE; - } - - if (!filter_wm_classes || !filter_wm_classes[0]) - return FALSE; - - filtered = TRUE; - - meta_error_trap_push (display); - success = XGetClassHint (display->xdisplay, xwindow, &class_hint); - - if (success) - { - for (i = 0; filter_wm_classes[i]; i++) - { - if (strcmp (class_hint.res_class, filter_wm_classes[i]) == 0) - { - filtered = FALSE; - break; - } - } - - XFree (class_hint.res_name); - XFree (class_hint.res_class); - } - - if (filtered) - { - /* We want to try and get the window managed by the next WM that come along, - * so we need to make sure that windows that are requested to be mapped while - * Mutter is running (!must_be_viewable), or windows already viewable at startup - * get a non-withdrawn WM_STATE property. Previously unmapped windows are left - * with whatever WM_STATE property they had. - */ - if (!must_be_viewable || attrs->map_state == IsViewable) - { - gulong old_state; - - if (!meta_prop_get_cardinal_with_atom_type (display, xwindow, - display->atom_WM_STATE, - display->atom_WM_STATE, - &old_state)) - old_state = WithdrawnState; - - if (old_state == WithdrawnState) - set_wm_state_on_xwindow (display, xwindow, NormalState); - } - - /* Make sure filtered windows are hidden from view */ - XUnmapWindow (display->xdisplay, xwindow); - } - - meta_error_trap_pop (display); - - return filtered; -} - gboolean meta_window_should_attach_to_parent (MetaWindow *window) { @@ -841,192 +740,56 @@ sync_client_window_mapped (MetaWindow *window) meta_error_trap_pop (window->display); } -MetaWindow* -meta_window_new (MetaDisplay *display, - Window xwindow, - gboolean must_be_viewable, - MetaCompEffect effect) +static void +meta_window_update_desc (MetaWindow *window) +{ + g_clear_pointer (&window->desc, g_free); + + if (window->title) + window->desc = g_strdup_printf ("0x%lx (%.10s)", window->xwindow, window->title); + else + window->desc = g_strdup_printf ("0x%lx", window->xwindow); +} + +MetaWindow * +_meta_window_shared_new (MetaDisplay *display, + MetaScreen *screen, + MetaWindowClientType client_type, + MetaWaylandSurface *surface, + Window xwindow, + gulong existing_wm_state, + MetaCompEffect effect, + XWindowAttributes *attrs) { - XWindowAttributes attrs; MetaWindow *window; - GSList *tmp; MetaWorkspace *space; - gulong existing_wm_state; - gulong event_mask; MetaMoveResizeFlags flags; - MetaScreen *screen; - meta_verbose ("Attempting to manage 0x%lx\n", xwindow); - - if (meta_display_xwindow_is_a_no_focus_window (display, xwindow)) - { - meta_verbose ("Not managing no_focus_window 0x%lx\n", - xwindow); - return NULL; - } - - meta_error_trap_push (display); /* Push a trap over all of window - * creation, to reduce XSync() calls - */ - /* - * This function executes without any server grabs held. This means that - * the window could have already gone away, or could go away at any point, - * so we must be careful with X error handling. - */ - - if (!XGetWindowAttributes (display->xdisplay, xwindow, &attrs)) - { - meta_verbose ("Failed to get attributes for window 0x%lx\n", - xwindow); - goto error; - } - - screen = NULL; - for (tmp = display->screens; tmp != NULL; tmp = tmp->next) - { - MetaScreen *scr = tmp->data; - - if (scr->xroot == attrs.root) - { - screen = tmp->data; - break; - } - } - - g_assert (screen); - - /* A black list of override redirect windows that we don't need to manage: */ - if (attrs.override_redirect && - (xwindow == screen->no_focus_window || - xwindow == screen->flash_window || - xwindow == screen->wm_sn_selection_window || - attrs.class == InputOnly || - /* any windows created via meta_create_offscreen_window: */ - (attrs.x == -100 && attrs.y == -100 - && attrs.width == 1 && attrs.height == 1) || - xwindow == screen->wm_cm_selection_window || - xwindow == screen->guard_window || - (display->compositor && - xwindow == XCompositeGetOverlayWindow (display->xdisplay, - screen->xroot) - ) - ) - ) { - meta_verbose ("Not managing our own windows\n"); - goto error; - } - - if (maybe_filter_window (display, xwindow, must_be_viewable, &attrs)) - { - meta_verbose ("Not managing filtered window\n"); - goto error; - } + g_assert (attrs != NULL); - meta_verbose ("must_be_viewable = %d attrs.map_state = %d (%s)\n", - must_be_viewable, - attrs.map_state, - (attrs.map_state == IsUnmapped) ? + meta_verbose ("attrs->map_state = %d (%s)\n", + attrs->map_state, + (attrs->map_state == IsUnmapped) ? "IsUnmapped" : - (attrs.map_state == IsViewable) ? + (attrs->map_state == IsViewable) ? "IsViewable" : - (attrs.map_state == IsUnviewable) ? + (attrs->map_state == IsUnviewable) ? "IsUnviewable" : "(unknown)"); - existing_wm_state = WithdrawnState; - if (must_be_viewable && attrs.map_state != IsViewable) - { - /* Only manage if WM_STATE is IconicState or NormalState */ - gulong state; - - /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */ - if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow, - display->atom_WM_STATE, - display->atom_WM_STATE, - &state) && - (state == IconicState || state == NormalState))) - { - meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow); - goto error; - } - - existing_wm_state = state; - meta_verbose ("WM_STATE of %lx = %s\n", xwindow, - wm_state_to_string (existing_wm_state)); - } - - /* - * XAddToSaveSet can only be called on windows created by a different client. - * with Mutter we want to be able to create manageable windows from within - * the process (such as a dummy desktop window). As we do not want this - * call failing to prevent the window from being managed, we call this - * before creating the return-checked error trap. - */ - XAddToSaveSet (display->xdisplay, xwindow); - - meta_error_trap_push_with_return (display); - - event_mask = PropertyChangeMask | ColormapChangeMask; - if (attrs.override_redirect) - event_mask |= StructureNotifyMask; - - /* If the window is from this client (a menu, say) we need to augment - * the event mask, not replace it. For windows from other clients, - * attrs.your_event_mask will be empty at this point. - */ - XSelectInput (display->xdisplay, xwindow, attrs.your_event_mask | event_mask); - - { - unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; - XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; - - meta_core_add_old_event_mask (display->xdisplay, xwindow, &mask); - - XISetMask (mask.mask, XI_Enter); - XISetMask (mask.mask, XI_Leave); - XISetMask (mask.mask, XI_FocusIn); - XISetMask (mask.mask, XI_FocusOut); - - XISelectEvents (display->xdisplay, xwindow, &mask, 1); - } - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display)) - XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask); -#endif - - /* Get rid of any borders */ - if (attrs.border_width != 0) - XSetWindowBorderWidth (display->xdisplay, xwindow, 0); - - /* Get rid of weird gravities */ - if (attrs.win_gravity != NorthWestGravity) - { - XSetWindowAttributes set_attrs; - - set_attrs.win_gravity = NorthWestGravity; - - XChangeWindowAttributes (display->xdisplay, - xwindow, - CWWinGravity, - &set_attrs); - } - - if (meta_error_trap_pop_with_return (display) != Success) - { - meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n", - xwindow); - goto error; - } - - - window = g_object_new (META_TYPE_WINDOW, NULL); + if (client_type == META_WINDOW_CLIENT_TYPE_X11) + window = g_object_new (META_TYPE_WINDOW_X11, NULL); + else + window = g_object_new (META_TYPE_WINDOW_WAYLAND, NULL); window->constructing = TRUE; window->dialog_pid = -1; + window->client_type = client_type; + window->surface = surface; window->xwindow = xwindow; + window->surface_mapped = FALSE; /* this is in window->screen->display, but that's too annoying to * type @@ -1043,24 +806,24 @@ meta_window_new (MetaDisplay *display, window->screen = screen; - window->desc = g_strdup_printf ("0x%lx", window->xwindow); + meta_window_update_desc (window); - window->override_redirect = attrs.override_redirect; + window->override_redirect = attrs->override_redirect; /* avoid tons of stack updates */ meta_stack_freeze (window->screen->stack); - window->rect.x = attrs.x; - window->rect.y = attrs.y; - window->rect.width = attrs.width; - window->rect.height = attrs.height; + window->rect.x = attrs->x; + window->rect.y = attrs->y; + window->rect.width = attrs->width; + window->rect.height = attrs->height; /* And border width, size_hints are the "request" */ - window->border_width = attrs.border_width; - window->size_hints.x = attrs.x; - window->size_hints.y = attrs.y; - window->size_hints.width = attrs.width; - window->size_hints.height = attrs.height; + window->border_width = attrs->border_width; + window->size_hints.x = attrs->x; + window->size_hints.y = attrs->y; + window->size_hints.width = attrs->width; + window->size_hints.height = attrs->height; /* initialize the remaining size_hints as if size_hints.flags were zero */ meta_set_normal_hints (window, NULL); @@ -1068,18 +831,15 @@ meta_window_new (MetaDisplay *display, window->saved_rect = window->rect; window->user_rect = window->rect; - window->depth = attrs.depth; - window->xvisual = attrs.visual; - window->colormap = attrs.colormap; + window->depth = attrs->depth; + window->xvisual = attrs->visual; window->title = NULL; - window->icon_name = NULL; window->icon = NULL; window->mini_icon = NULL; meta_icon_cache_init (&window->icon_cache); window->wm_hints_pixmap = None; window->wm_hints_mask = None; - window->wm_hints_urgent = FALSE; window->frame = NULL; window->has_focus = FALSE; @@ -1105,8 +865,9 @@ meta_window_new (MetaDisplay *display, window->minimized = FALSE; window->tab_unminimized = FALSE; window->iconic = FALSE; - window->mapped = attrs.map_state != IsUnmapped; + window->mapped = attrs->map_state != IsUnmapped; window->hidden = FALSE; + window->known_to_compositor = FALSE; window->visible_to_compositor = FALSE; window->pending_compositor_effect = effect; /* if already mapped, no need to worry about focus-on-first-time-showing */ @@ -1132,7 +893,7 @@ meta_window_new (MetaDisplay *display, window->user_time_window = None; window->take_focus = FALSE; window->delete_window = FALSE; - window->net_wm_ping = FALSE; + window->can_ping = FALSE; window->input = TRUE; window->calc_placement = FALSE; window->shaken_loose = FALSE; @@ -1149,7 +910,11 @@ meta_window_new (MetaDisplay *display, window->mwm_has_move_func = TRUE; window->mwm_has_resize_func = TRUE; - window->decorated = TRUE; + if (client_type == META_WINDOW_CLIENT_TYPE_X11) + window->decorated = TRUE; + else + window->decorated = FALSE; + window->has_close_func = TRUE; window->has_minimize_func = TRUE; window->has_maximize_func = TRUE; @@ -1162,11 +927,8 @@ meta_window_new (MetaDisplay *display, window->always_sticky = FALSE; - window->wm_state_modal = FALSE; window->skip_taskbar = FALSE; window->skip_pager = FALSE; - window->wm_state_skip_taskbar = FALSE; - window->wm_state_skip_pager = FALSE; window->wm_state_above = FALSE; window->wm_state_below = FALSE; window->wm_state_demands_attention = FALSE; @@ -1186,17 +948,9 @@ meta_window_new (MetaDisplay *display, window->transient_parent_is_root_window = FALSE; window->type = META_WINDOW_NORMAL; - window->type_atom = None; window->struts = NULL; - window->using_net_wm_name = FALSE; - window->using_net_wm_visible_name = FALSE; - window->using_net_wm_icon_name = FALSE; - window->using_net_wm_visible_icon_name = FALSE; - - window->need_reread_icon = TRUE; - window->layer = META_LAYER_LAST; /* invalid value */ window->stack_position = -1; window->initial_workspace = 0; /* not used */ @@ -1208,21 +962,6 @@ meta_window_new (MetaDisplay *display, window->tile_match = NULL; - if (window->override_redirect) - { - window->decorated = FALSE; - window->always_sticky = TRUE; - window->has_close_func = FALSE; - window->has_shade_func = FALSE; - window->has_move_func = FALSE; - window->has_resize_func = FALSE; - } - - meta_display_register_x_window (display, &window->xwindow, window); - - meta_window_update_shape_region_x11 (window); - meta_window_update_input_region_x11 (window); - /* Assign this #MetaWindow a sequence number which can be used * for sorting. */ @@ -1230,23 +969,18 @@ meta_window_new (MetaDisplay *display, window->opacity = 0xFF; - /* assign the window to its group, or create a new group if needed - */ - window->group = NULL; - window->xgroup_leader = None; - meta_window_compute_group (window); - - meta_window_load_initial_properties (window); + META_WINDOW_GET_CLASS (window)->manage (window); - if (!window->override_redirect) + if (window->override_redirect) { - update_sm_hints (window); /* must come after transient_for */ - - meta_window_update_role (window); + window->decorated = FALSE; + window->always_sticky = TRUE; + window->has_close_func = FALSE; + window->has_shade_func = FALSE; + window->has_move_func = FALSE; + window->has_resize_func = FALSE; } - meta_window_update_net_wm_type (window); - if (!window->override_redirect) meta_window_update_icon_now (window); @@ -1282,11 +1016,6 @@ meta_window_new (MetaDisplay *display, * can use this time as a fallback. */ if (!window->override_redirect && !window->net_wm_user_time_set) { - MetaWindow *parent = NULL; - if (window->xtransient_for) - parent = meta_display_lookup_x_window (window->display, - window->xtransient_for); - /* First, maybe the app was launched with startup notification using an * obsolete version of the spec; use that timestamp if it exists. */ @@ -1295,8 +1024,8 @@ meta_window_new (MetaDisplay *display, * being recorded as a fallback for potential transients */ window->net_wm_user_time = window->initial_timestamp; - else if (parent != NULL) - meta_window_set_user_time(window, parent->net_wm_user_time); + else if (window->transient_for != NULL) + meta_window_set_user_time (window, window->transient_for->net_wm_user_time); else /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just * being recorded as a fallback for potential transients @@ -1307,7 +1036,7 @@ meta_window_new (MetaDisplay *display, window->attached = meta_window_should_attach_to_parent (window); if (window->attached) - recalc_window_features (window); + meta_window_recalc_features (window); if (window->decorated) meta_window_ensure_frame (window); @@ -1376,21 +1105,16 @@ meta_window_new (MetaDisplay *display, if (!window->override_redirect) { if (window->workspace == NULL && - window->xtransient_for != None) + window->transient_for != NULL) { /* Try putting dialog on parent's workspace */ - MetaWindow *parent; - - parent = meta_display_lookup_x_window (window->display, - window->xtransient_for); - - if (parent && parent->workspace) + if (window->transient_for->workspace) { meta_topic (META_DEBUG_PLACEMENT, "Putting window %s on same workspace as parent %s\n", - window->desc, parent->desc); + window->desc, window->transient_for->desc); - if (parent->on_all_workspaces_requested) + if (window->transient_for->on_all_workspaces_requested) { window->on_all_workspaces_requested = TRUE; window->on_all_workspaces = TRUE; @@ -1398,7 +1122,7 @@ meta_window_new (MetaDisplay *display, /* this will implicitly add to the appropriate MRU lists */ - meta_workspace_add_window (parent->workspace, window); + meta_workspace_add_window (window->transient_for->workspace, window); } } @@ -1471,8 +1195,8 @@ meta_window_new (MetaDisplay *display, set_net_wm_state (window); } - if (screen->display->compositor) - meta_compositor_add_window (screen->display->compositor, window); + meta_compositor_add_window (screen->display->compositor, window); + window->known_to_compositor = TRUE; /* Sync stack changes */ meta_stack_thaw (window->screen->stack); @@ -1511,8 +1235,6 @@ meta_window_new (MetaDisplay *display, !window->initially_iconic) unminimize_window_and_all_transient_parents (window); - meta_error_trap_pop (display); /* pop the XSync()-reducing trap */ - window->constructing = FALSE; meta_display_notify_window_created (display, window); @@ -1520,14 +1242,63 @@ meta_window_new (MetaDisplay *display, if (window->wm_state_demands_attention) g_signal_emit_by_name (window->display, "window-demands-attention", window); - if (window->wm_hints_urgent) - g_signal_emit_by_name (window->display, "window-marked-urgent", window); - return window; +} + +MetaWindow * +meta_window_wayland_new (MetaDisplay *display, + MetaWaylandSurface *surface) +{ + XWindowAttributes attrs; + MetaScreen *scr = display->screen; + MetaWindow *window; + + attrs.x = 0; + attrs.y = 0; + attrs.width = 1; + attrs.height = 1; + attrs.border_width = 0; + attrs.depth = 24; + attrs.visual = NULL; + attrs.root = scr->xroot; + attrs.class = InputOutput; + attrs.bit_gravity = NorthWestGravity; + attrs.win_gravity = NorthWestGravity; + attrs.backing_store = 0; + attrs.backing_planes = ~0; + attrs.backing_pixel = 0; + attrs.save_under = 0; + attrs.colormap = 0; + attrs.map_installed = 1; + attrs.map_state = IsUnmapped; + attrs.all_event_masks = ~0; + attrs.your_event_mask = 0; + attrs.do_not_propagate_mask = 0; + attrs.override_redirect = 0; + attrs.screen = scr->xscreen; + + /* XXX: Note: In the Wayland case we currently still trap X errors while + * creating a MetaWindow because we will still be making various redundant + * X requests (passing a window xid of None) until we thoroughly audit all + * the code to make sure it knows about non X based clients... + */ + meta_error_trap_push (display); /* Push a trap over all of window + * creation, to reduce XSync() calls + */ + + window = _meta_window_shared_new (display, + scr, + META_WINDOW_CLIENT_TYPE_WAYLAND, + surface, + None, + WithdrawnState, + META_COMP_EFFECT_CREATE, + &attrs); + window->can_ping = TRUE; + + meta_error_trap_pop (display); /* pop the XSync()-reducing trap */ -error: - meta_error_trap_pop (display); - return NULL; + return window; } /* This function should only be called from the end of meta_window_new_with_attrs () */ @@ -1694,15 +1465,21 @@ meta_window_unmanage (MetaWindow *window, meta_verbose ("Unmanaging 0x%lx\n", window->xwindow); - if (window->display->compositor) - { - if (window->visible_to_compositor) - meta_compositor_hide_window (window->display->compositor, window, - META_COMP_EFFECT_DESTROY); + /* This needs to happen for both Wayland and XWayland clients, + * so it can't be in MetaWindowWayland. */ + if (window->surface) + meta_wayland_surface_set_window (window->surface, NULL); - meta_compositor_remove_window (window->display->compositor, window); + if (window->visible_to_compositor) + { + window->visible_to_compositor = FALSE; + meta_compositor_hide_window (window->display->compositor, window, + META_COMP_EFFECT_DESTROY); } + meta_compositor_remove_window (window->display->compositor, window); + window->known_to_compositor = FALSE; + if (window->display->window_with_menu == window) { meta_ui_window_menu_free (window->display->window_menu); @@ -1802,12 +1579,6 @@ meta_window_unmanage (MetaWindow *window, if (window->maximized_horizontally || window->maximized_vertically) unmaximize_window_before_freeing (window); - /* The XReparentWindow call in meta_window_destroy_frame() moves the - * window so we need to send a configure notify; see bug 399552. (We - * also do this just in case a window got unmaximized.) - */ - send_configure_notify (window); - meta_window_unqueue (window, META_QUEUE_CALC_SHOWING | META_QUEUE_MOVE_RESIZE | META_QUEUE_UPDATE_ICON); @@ -1843,110 +1614,24 @@ meta_window_unmanage (MetaWindow *window, meta_window_destroy_sync_request_alarm (window); - if (window->frame) - meta_window_destroy_frame (window); - /* If an undecorated window is being withdrawn, that will change the * stack as presented to the compositing manager, without actually * changing the stacking order of X windows. */ meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker); - if (window->withdrawn) - { - /* We need to clean off the window's state so it - * won't be restored if the app maps it again. - */ - meta_error_trap_push (window->display); - meta_verbose ("Cleaning state from window %s\n", window->desc); - XDeleteProperty (window->display->xdisplay, - window->xwindow, - window->display->atom__NET_WM_DESKTOP); - XDeleteProperty (window->display->xdisplay, - window->xwindow, - window->display->atom__NET_WM_STATE); - XDeleteProperty (window->display->xdisplay, - window->xwindow, - window->display->atom__NET_WM_FULLSCREEN_MONITORS); - set_wm_state (window); - meta_error_trap_pop (window->display); - } - else - { - /* We need to put WM_STATE so that others will understand it on - * restart. - */ - if (!window->minimized) - { - meta_error_trap_push (window->display); - set_wm_state (window); - meta_error_trap_pop (window->display); - } - - /* If we're unmanaging a window that is not withdrawn, then - * either (a) mutter is exiting, in which case we need to map - * the window so the next WM will know that it's not Withdrawn, - * or (b) we want to create a new MetaWindow to replace the - * current one, which will happen automatically if we re-map - * the X Window. - */ - meta_error_trap_push (window->display); - XMapWindow (window->display->xdisplay, - window->xwindow); - meta_error_trap_pop (window->display); - } - meta_window_ungrab_keys (window); meta_display_ungrab_window_buttons (window->display, window->xwindow); meta_display_ungrab_focus_window_button (window->display, window); if (window->display->autoraise_window == window) meta_display_remove_autoraise_callback (window->display); - meta_display_unregister_x_window (window->display, window->xwindow); - - - meta_error_trap_push (window->display); - - /* Put back anything we messed up */ - if (window->border_width != 0) - XSetWindowBorderWidth (window->display->xdisplay, - window->xwindow, - window->border_width); - - /* No save set */ - XRemoveFromSaveSet (window->display->xdisplay, - window->xwindow); - - /* Even though the window is now unmanaged, we can't unselect events. This - * window might be a window from this process, like a GdkMenu, in - * which case it will have pointer events and so forth selected - * for it by GDK. There's no way to disentangle those events from the events - * we've selected. Even for a window from a different X client, - * GDK could also have selected events for it for IPC purposes, so we - * can't unselect in that case either. - * - * Similarly, we can't unselected for events on window->user_time_window. - * It might be our own GDK focus window, or it might be a window that a - * different client is using for multiple different things: - * _NET_WM_USER_TIME_WINDOW and IPC, perhaps. - */ - - if (window->user_time_window != None) - { - meta_display_unregister_x_window (window->display, - window->user_time_window); - window->user_time_window = None; - } - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (window->display)) - XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask); -#endif + META_WINDOW_GET_CLASS (window)->unmanage (window); - meta_error_trap_pop (window->display); + if (window->frame) + meta_window_destroy_frame (window); meta_prefs_remove_listener (prefs_changed_callback, window); - meta_screen_queue_check_fullscreen (window->screen); g_signal_emit (window, window_signals[UNMANAGED], 0); @@ -2008,155 +1693,17 @@ meta_window_update_on_all_workspaces (MetaWindow *window) } static void -set_wm_state_on_xwindow (MetaDisplay *display, - Window xwindow, - int state) -{ - unsigned long data[2]; - - /* Mutter doesn't use icon windows, so data[1] should be None - * according to the ICCCM 2.0 Section 4.1.3.1. - */ - data[0] = state; - data[1] = None; - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, xwindow, - display->atom_WM_STATE, - display->atom_WM_STATE, - 32, PropModeReplace, (guchar*) data, 2); - meta_error_trap_pop (display); -} - -static void set_wm_state (MetaWindow *window) { - int state; - - if (window->withdrawn) - state = WithdrawnState; - else if (window->iconic) - state = IconicState; - else - state = NormalState; - - set_wm_state_on_xwindow (window->display, window->xwindow, state); + if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) + meta_window_x11_set_wm_state (window); } static void set_net_wm_state (MetaWindow *window) { - int i; - unsigned long data[13]; - - i = 0; - if (window->shaded) - { - data[i] = window->display->atom__NET_WM_STATE_SHADED; - ++i; - } - if (window->wm_state_modal) - { - data[i] = window->display->atom__NET_WM_STATE_MODAL; - ++i; - } - if (window->skip_pager) - { - data[i] = window->display->atom__NET_WM_STATE_SKIP_PAGER; - ++i; - } - if (window->skip_taskbar) - { - data[i] = window->display->atom__NET_WM_STATE_SKIP_TASKBAR; - ++i; - } - if (window->maximized_horizontally) - { - data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_HORZ; - ++i; - } - if (window->maximized_vertically) - { - data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_VERT; - ++i; - } - if (window->fullscreen) - { - data[i] = window->display->atom__NET_WM_STATE_FULLSCREEN; - ++i; - } - if (!meta_window_showing_on_its_workspace (window) || window->shaded) - { - data[i] = window->display->atom__NET_WM_STATE_HIDDEN; - ++i; - } - if (window->wm_state_above) - { - data[i] = window->display->atom__NET_WM_STATE_ABOVE; - ++i; - } - if (window->wm_state_below) - { - data[i] = window->display->atom__NET_WM_STATE_BELOW; - ++i; - } - if (window->wm_state_demands_attention) - { - data[i] = window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION; - ++i; - } - if (window->on_all_workspaces_requested) - { - data[i] = window->display->atom__NET_WM_STATE_STICKY; - ++i; - } - if (meta_window_appears_focused (window)) - { - data[i] = window->display->atom__NET_WM_STATE_FOCUSED; - ++i; - } - - meta_verbose ("Setting _NET_WM_STATE with %d atoms\n", i); - - meta_error_trap_push (window->display); - XChangeProperty (window->display->xdisplay, window->xwindow, - window->display->atom__NET_WM_STATE, - XA_ATOM, - 32, PropModeReplace, (guchar*) data, i); - meta_error_trap_pop (window->display); - - if (window->fullscreen) - { - if (window->fullscreen_monitors[0] >= 0) - { - data[0] = meta_screen_monitor_index_to_xinerama_index (window->screen, - window->fullscreen_monitors[0]); - data[1] = meta_screen_monitor_index_to_xinerama_index (window->screen, - window->fullscreen_monitors[1]); - data[2] = meta_screen_monitor_index_to_xinerama_index (window->screen, - window->fullscreen_monitors[2]); - data[3] = meta_screen_monitor_index_to_xinerama_index (window->screen, - window->fullscreen_monitors[3]); - - meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n"); - meta_error_trap_push (window->display); - XChangeProperty (window->display->xdisplay, - window->xwindow, - window->display->atom__NET_WM_FULLSCREEN_MONITORS, - XA_CARDINAL, 32, PropModeReplace, - (guchar*) data, 4); - meta_error_trap_pop (window->display); - } - else - { - meta_verbose ("Clearing _NET_WM_FULLSCREEN_MONITORS\n"); - meta_error_trap_push (window->display); - XDeleteProperty (window->display->xdisplay, - window->xwindow, - window->display->atom__NET_WM_FULLSCREEN_MONITORS); - meta_error_trap_pop (window->display); - } - } + if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) + meta_window_x11_set_net_wm_state (window); } /** @@ -2262,6 +1809,9 @@ meta_window_should_be_showing (MetaWindow *window) { gboolean on_workspace; + if (!window->surface_mapped) + return FALSE; + meta_verbose ("Should be showing for window %s\n", window->desc); /* See if we're on the workspace */ @@ -2711,8 +2261,8 @@ intervening_user_event_occurred (MetaWindow *window) * behavior is worthwhile. The basic idea is to get more feedback about how * usage scenarios of "strict" focus users and what they expect. See #326159. */ -gboolean -__window_is_terminal (MetaWindow *window) +static gboolean +window_is_terminal (MetaWindow *window) { if (window == NULL || window->res_class == NULL) return FALSE; @@ -2788,7 +2338,7 @@ window_state_on_map (MetaWindow *window, if (*takes_focus && meta_prefs_get_focus_new_windows () == G_DESKTOP_FOCUS_NEW_WINDOWS_STRICT && !window->display->allow_terminal_deactivation && - __window_is_terminal (window->display->focus_window) && + window_is_terminal (window->display->focus_window) && !meta_window_is_ancestor_of_transient (window->display->focus_window, window)) { @@ -3067,27 +2617,24 @@ meta_window_show (MetaWindow *window) if (!window->visible_to_compositor) { + MetaCompEffect effect = META_COMP_EFFECT_NONE; + window->visible_to_compositor = TRUE; - if (window->display->compositor) + switch (window->pending_compositor_effect) { - MetaCompEffect effect = META_COMP_EFFECT_NONE; - - switch (window->pending_compositor_effect) - { - case META_COMP_EFFECT_CREATE: - case META_COMP_EFFECT_UNMINIMIZE: - effect = window->pending_compositor_effect; - break; - case META_COMP_EFFECT_NONE: - case META_COMP_EFFECT_DESTROY: - case META_COMP_EFFECT_MINIMIZE: - break; - } - - meta_compositor_show_window (window->display->compositor, - window, effect); + case META_COMP_EFFECT_CREATE: + case META_COMP_EFFECT_UNMINIMIZE: + effect = window->pending_compositor_effect; + break; + case META_COMP_EFFECT_NONE: + case META_COMP_EFFECT_DESTROY: + case META_COMP_EFFECT_MINIMIZE: + break; } + + meta_compositor_show_window (window->display->compositor, + window, effect); } /* We don't want to worry about all cases from inside @@ -3130,6 +2677,9 @@ meta_window_show (MetaWindow *window) if (did_show) meta_screen_queue_check_fullscreen (window->screen); + if (did_show && window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) + meta_wayland_compositor_repick (meta_wayland_compositor_get_default ()); + /* * Now that we have shown the window, we no longer want to consider the * initial timestamp in any subsequent deliberations whether to focus this @@ -3157,26 +2707,23 @@ meta_window_hide (MetaWindow *window) if (window->visible_to_compositor) { + MetaCompEffect effect = META_COMP_EFFECT_NONE; + window->visible_to_compositor = FALSE; - if (window->display->compositor) + switch (window->pending_compositor_effect) { - MetaCompEffect effect = META_COMP_EFFECT_NONE; - - switch (window->pending_compositor_effect) - { - case META_COMP_EFFECT_CREATE: - case META_COMP_EFFECT_UNMINIMIZE: - case META_COMP_EFFECT_NONE: - break; - case META_COMP_EFFECT_DESTROY: - case META_COMP_EFFECT_MINIMIZE: - effect = window->pending_compositor_effect; - break; - } - - meta_compositor_hide_window (window->display->compositor, window, effect); + case META_COMP_EFFECT_CREATE: + case META_COMP_EFFECT_UNMINIMIZE: + case META_COMP_EFFECT_NONE: + break; + case META_COMP_EFFECT_DESTROY: + case META_COMP_EFFECT_MINIMIZE: + effect = window->pending_compositor_effect; + break; } + + meta_compositor_hide_window (window->display->compositor, window, effect); } did_hide = FALSE; @@ -3424,9 +2971,12 @@ meta_window_maximize_internal (MetaWindow *window, if (maximize_horizontally || maximize_vertically) window->force_save_user_rect = FALSE; - recalc_window_features (window); + meta_window_recalc_features (window); set_net_wm_state (window); + if (window->surface && window->maximized_horizontally && window->maximized_vertically) + meta_wayland_surface_send_maximized (window->surface); + g_object_freeze_notify (G_OBJECT (window)); g_object_notify (G_OBJECT (window), "maximized-horizontally"); g_object_notify (G_OBJECT (window), "maximized-vertically"); @@ -3439,6 +2989,8 @@ meta_window_maximize (MetaWindow *window, { MetaRectangle *saved_rect = NULL; gboolean maximize_horizontally, maximize_vertically; + MetaRectangle old_rect; + MetaRectangle new_rect; g_return_if_fail (!window->override_redirect); @@ -3488,27 +3040,15 @@ meta_window_maximize (MetaWindow *window, directions, saved_rect); - if (window->display->compositor) - { - MetaRectangle old_rect; - MetaRectangle new_rect; - - meta_window_get_frame_rect (window, &old_rect); + meta_window_get_frame_rect (window, &old_rect); - meta_window_move_resize_now (window); + meta_window_move_resize_now (window); - meta_window_get_frame_rect (window, &new_rect); - meta_compositor_maximize_window (window->display->compositor, - window, - &old_rect, - &new_rect); - } - else - { - /* move_resize with new maximization constraints - */ - meta_window_queue(window, META_QUEUE_MOVE_RESIZE); - } + meta_window_get_frame_rect (window, &new_rect); + meta_compositor_maximize_window (window->display->compositor, + window, + &old_rect, + &new_rect); } } @@ -3668,6 +3208,8 @@ void meta_window_tile (MetaWindow *window) { MetaMaximizeFlags directions; + MetaRectangle old_rect; + MetaRectangle new_rect; /* Don't do anything if no tiling is requested */ if (window->tile_mode == META_TILE_NONE) @@ -3681,31 +3223,19 @@ meta_window_tile (MetaWindow *window) meta_window_maximize_internal (window, directions, NULL); meta_screen_update_tile_preview (window->screen, FALSE); - if (window->display->compositor) - { - MetaRectangle old_rect; - MetaRectangle new_rect; + meta_window_get_frame_rect (window, &old_rect); - meta_window_get_frame_rect (window, &old_rect); + meta_window_move_resize_now (window); - meta_window_move_resize_now (window); + meta_window_get_frame_rect (window, &new_rect); + meta_compositor_maximize_window (window->display->compositor, + window, + &old_rect, + &new_rect); - meta_window_get_frame_rect (window, &new_rect); - meta_compositor_maximize_window (window->display->compositor, - window, - &old_rect, - &new_rect); - - if (window->frame) - meta_ui_queue_frame_draw (window->screen->ui, - window->frame->xwindow); - } - else - { - /* move_resize with new tiling constraints - */ - meta_window_queue (window, META_QUEUE_MOVE_RESIZE); - } + if (window->frame) + meta_ui_queue_frame_draw (window->screen->ui, + window->frame->xwindow); } static gboolean @@ -3778,6 +3308,7 @@ meta_window_unmaximize_internal (MetaWindow *window, int gravity) { gboolean unmaximize_horizontally, unmaximize_vertically; + MetaRectangle new_rect; g_return_if_fail (!window->override_redirect); @@ -3814,7 +3345,7 @@ meta_window_unmaximize_internal (MetaWindow *window, window->maximized_vertically = window->maximized_vertically && !unmaximize_vertically; - /* recalc_window_features() will eventually clear the cached frame + /* recalc_features() will eventually clear the cached frame * extents, but we need the correct frame extents in the code below, * so invalidate the old frame extents manually up front. */ @@ -3862,34 +3393,19 @@ meta_window_unmaximize_internal (MetaWindow *window, */ ensure_size_hints_satisfied (&target_rect, &window->size_hints); - if (window->display->compositor) - { - MetaRectangle new_rect; - - meta_window_move_resize_internal (window, - META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION, - gravity, - target_rect.x, - target_rect.y, - target_rect.width, - target_rect.height); - - meta_window_get_frame_rect (window, &new_rect); - meta_compositor_unmaximize_window (window->display->compositor, - window, - &old_rect, - &new_rect); - } - else - { - meta_window_move_resize_internal (window, - META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION, - gravity, - target_rect.x, - target_rect.y, - target_rect.width, - target_rect.height); - } + meta_window_move_resize_internal (window, + META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION, + gravity, + target_rect.x, + target_rect.y, + target_rect.width, + target_rect.height); + + meta_window_get_frame_rect (window, &new_rect); + meta_compositor_unmaximize_window (window->display->compositor, + window, + &old_rect, + &new_rect); /* Make sure user_rect is current. */ @@ -3908,14 +3424,17 @@ meta_window_unmaximize_internal (MetaWindow *window, window->display->grab_anchor_window_pos = window->user_rect; } - recalc_window_features (window); + meta_window_recalc_features (window); set_net_wm_state (window); } - g_object_freeze_notify (G_OBJECT (window)); - g_object_notify (G_OBJECT (window), "maximized-horizontally"); - g_object_notify (G_OBJECT (window), "maximized-vertically"); - g_object_thaw_notify (G_OBJECT (window)); + if (window->surface && !window->maximized_horizontally && !window->maximized_vertically) + meta_wayland_surface_send_unmaximized (window->surface); + + g_object_freeze_notify (G_OBJECT (window)); + g_object_notify (G_OBJECT (window), "maximized-horizontally"); + g_object_notify (G_OBJECT (window), "maximized-vertically"); + g_object_thaw_notify (G_OBJECT (window)); } void @@ -4012,12 +3531,15 @@ meta_window_make_fullscreen_internal (MetaWindow *window) meta_window_raise (window); meta_stack_thaw (window->screen->stack); - recalc_window_features (window); + meta_window_recalc_features (window); set_net_wm_state (window); /* For the auto-minimize feature, if we fail to get focus */ meta_screen_queue_check_fullscreen (window->screen); + if (window->surface) + meta_wayland_surface_send_fullscreened (window->surface); + g_object_notify (G_OBJECT (window), "fullscreen"); } } @@ -4058,7 +3580,7 @@ meta_window_unmake_fullscreen (MetaWindow *window) /* Need to update window->has_resize_func before we move_resize() */ - recalc_window_features (window); + meta_window_recalc_features (window); set_net_wm_state (window); meta_window_move_resize (window, @@ -4074,6 +3596,9 @@ meta_window_unmake_fullscreen (MetaWindow *window) meta_window_update_layer (window); + if (window->surface) + meta_wayland_surface_send_unfullscreened (window->surface); + g_object_notify (G_OBJECT (window), "fullscreen"); } } @@ -4172,11 +3697,11 @@ unminimize_window_and_all_transient_parents (MetaWindow *window) meta_window_foreach_ancestor (window, unminimize_func, NULL); } -static void -window_activate (MetaWindow *window, - guint32 timestamp, - MetaClientType source_indication, - MetaWorkspace *workspace) +void +meta_window_activate_full (MetaWindow *window, + guint32 timestamp, + MetaClientType source_indication, + MetaWorkspace *workspace) { gboolean can_ignore_outdated_timestamps; meta_topic (META_DEBUG_FOCUS, @@ -4224,14 +3749,14 @@ window_activate (MetaWindow *window, /* For non-transient windows, we just set up a pulsing indicator, rather than move windows or workspaces. See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */ - if (window->xtransient_for == None && + if (window->transient_for == NULL && !meta_window_located_on_workspace (window, workspace)) { meta_window_set_demands_attention (window); /* We've marked it as demanding, don't need to do anything else. */ return; } - else if (window->xtransient_for != None) + else if (window->transient_for != NULL) { /* Move transients to current workspace - preference dialogs should appear over the source window. */ @@ -4269,7 +3794,7 @@ meta_window_activate (MetaWindow *window, * we were such. If we change the pager behavior later, we could revisit * this and just add extra flags to window_activate. */ - window_activate (window, timestamp, META_CLIENT_TYPE_PAGER, NULL); + meta_window_activate_full (window, timestamp, META_CLIENT_TYPE_PAGER, NULL); } void @@ -4279,11 +3804,7 @@ meta_window_activate_with_workspace (MetaWindow *window, { g_return_if_fail (!window->override_redirect); - /* We're not really a pager, but the behavior we want is the same as if - * we were such. If we change the pager behavior later, we could revisit - * this and just add extra flags to window_activate. - */ - window_activate (window, timestamp, META_CLIENT_TYPE_APPLICATION, workspace); + meta_window_activate_full (window, timestamp, META_CLIENT_TYPE_APPLICATION, workspace); } /* Manually fix all the weirdness explained in the big comment at the @@ -4421,12 +3942,6 @@ adjust_for_gravity (MetaWindow *window, } } -static gboolean -static_gravity_works (MetaDisplay *display) -{ - return display->static_gravity_works; -} - void meta_window_create_sync_request_alarm (MetaWindow *window) { @@ -4438,7 +3953,7 @@ meta_window_create_sync_request_alarm (MetaWindow *window) window->sync_request_alarm != None) return; - meta_error_trap_push_with_return (window->display); + meta_error_trap_push (window->display); /* In the new (extended style), the counter value is initialized by * the client before mapping the window. In the old style, we're @@ -4514,90 +4029,6 @@ meta_window_destroy_sync_request_alarm (MetaWindow *window) #endif /* HAVE_XSYNC */ } -#ifdef HAVE_XSYNC -static gboolean -sync_request_timeout (gpointer data) -{ - MetaWindow *window = data; - - window->sync_request_timeout_id = 0; - - /* We have now waited for more than a second for the - * application to respond to the sync request - */ - window->disable_sync = TRUE; - - /* Reset the wait serial, so we don't continue freezing - * window updates - */ - window->sync_request_wait_serial = 0; - meta_compositor_set_updates_frozen (window->display->compositor, window, - meta_window_updates_are_frozen (window)); - - if (window == window->display->grab_window && - meta_grab_op_is_resizing (window->display->grab_op)) - { - update_resize (window, - window->display->grab_last_user_action_was_snap, - window->display->grab_latest_motion_x, - window->display->grab_latest_motion_y, - TRUE); - } - - return FALSE; -} - -static void -send_sync_request (MetaWindow *window) -{ - XClientMessageEvent ev; - gint64 wait_serial; - - /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to - * increase the value, but for the new "extended" style we need to - * pick an even (unfrozen) value sufficiently ahead of the last serial - * that we received from the client; the same code still works - * for the old style. The increment of 240 is specified by the EWMH - * and is (1 second) * (60fps) * (an increment of 4 per frame). - */ - wait_serial = window->sync_request_serial + 240; - - window->sync_request_wait_serial = wait_serial; - - ev.type = ClientMessage; - ev.window = window->xwindow; - ev.message_type = window->display->atom_WM_PROTOCOLS; - ev.format = 32; - ev.data.l[0] = window->display->atom__NET_WM_SYNC_REQUEST; - /* FIXME: meta_display_get_current_time() is bad, but since calls - * come from meta_window_move_resize_internal (which in turn come - * from all over), I'm not sure what we can do to fix it. Do we - * want to use _roundtrip, though? - */ - ev.data.l[1] = meta_display_get_current_time (window->display); - ev.data.l[2] = wait_serial & G_GUINT64_CONSTANT(0xffffffff); - ev.data.l[3] = wait_serial >> 32; - ev.data.l[4] = window->extended_sync_request_counter ? 1 : 0; - - /* We don't need to trap errors here as we are already - * inside an error_trap_push()/pop() pair. - */ - XSendEvent (window->display->xdisplay, - window->xwindow, False, 0, (XEvent*) &ev); - - /* We give the window 1 sec to respond to _NET_WM_SYNC_REQUEST; - * if this time expires, we consider the window unresponsive - * and resize it unsynchonized. - */ - window->sync_request_timeout_id = g_timeout_add (1000, - sync_request_timeout, - window); - - meta_compositor_set_updates_frozen (window->display->compositor, window, - meta_window_updates_are_frozen (window)); -} -#endif - /** * meta_window_updates_are_frozen: * @window: a #MetaWindow @@ -4700,7 +4131,7 @@ meta_window_update_for_monitors_changed (MetaWindow *window) &new->rect); } -static void +void meta_window_update_monitor (MetaWindow *window) { const MetaMonitorInfo *old; @@ -4736,7 +4167,7 @@ meta_window_update_monitor (MetaWindow *window) /* If we're changing monitors, we need to update the has_maximize_func flag, * as the working area has changed. */ - recalc_window_features (window); + meta_window_recalc_features (window); } } @@ -4769,6 +4200,7 @@ meta_window_move_resize_internal (MetaWindow *window, * 2 | A not-resize-only ConfigureRequest/net_moveresize_window request * 3 | meta_window_move * 3 | meta_window_move_resize + * 4 | meta_window_move_resize_wayland * * For each of the cases, root_x_nw and root_y_nw must be treated as follows: * @@ -4779,42 +4211,38 @@ meta_window_move_resize_internal (MetaWindow *window, * coordinates are relative to some corner or side of the outer * window (except for the case of StaticGravity) and we want to * know the location of the upper left corner of the inner window. - * (3) These values are already the desired positon of the NW corner + * (3) These values are already the desired position of the NW corner * of the inner window + * (4) These values are already the desired position of the NW corner + * of the inner window (which is also the outer window, because + * we don't decorate wayland clients), and the client has acknowledged + * the window size change. */ - XWindowChanges values; - unsigned int mask; - gboolean need_configure_notify; - MetaFrameBorders borders; - gboolean need_move_client = FALSE; - gboolean need_move_frame = FALSE; - gboolean need_resize_client = FALSE; - gboolean need_resize_frame = FALSE; - int size_dx; - int size_dy; - gboolean frame_shape_changed = FALSE; gboolean is_configure_request; gboolean do_gravity_adjust; gboolean is_user_action; + gboolean is_wayland_resize; gboolean did_placement; - gboolean configure_frame_first; - gboolean use_static_gravity; /* used for the configure request, but may not be final * destination due to StaticGravity etc. */ - int client_move_x; - int client_move_y; MetaRectangle new_rect; MetaRectangle old_rect; + MetaRectangle requested_rect; + MetaMoveResizeResultFlags result; + MetaFrameBorders borders; g_return_if_fail (!window->override_redirect); is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0; do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0; is_user_action = (flags & META_IS_USER_ACTION) != 0; + is_wayland_resize = (flags & META_IS_WAYLAND_RESIZE) != 0; - /* The action has to be a move or a resize or both... */ - g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)); + /* The action has to be a move, a resize or the wayland client + * acking our choice of size. + */ + g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION | META_IS_WAYLAND_RESIZE)); /* We don't need it in the idle queue anymore. */ meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE); @@ -4828,13 +4256,14 @@ meta_window_move_resize_internal (MetaWindow *window, is_user_action ? " (user move/resize)" : "", old_rect.x, old_rect.y, old_rect.width, old_rect.height); - meta_frame_calc_borders (window->frame, - &borders); + meta_frame_calc_borders (window->frame, &borders); - new_rect.x = root_x_nw; - new_rect.y = root_y_nw; - new_rect.width = w; - new_rect.height = h; + requested_rect.x = root_x_nw; + requested_rect.y = root_y_nw; + requested_rect.width = w; + requested_rect.height = h; + + new_rect = requested_rect; /* If this is a resize only, the position should be ignored and * instead obtained by resizing the old rectangle according to the @@ -4872,328 +4301,31 @@ meta_window_move_resize_internal (MetaWindow *window, did_placement = !window->placed && window->calc_placement; - meta_window_constrain (window, - flags, - gravity, - &old_rect, - &new_rect); - - /* meta_window_constrain() might have maximized the window after placement, - * changing the borders. - */ - meta_frame_calc_borders (window->frame, &borders); - - w = new_rect.width; - h = new_rect.height; - root_x_nw = new_rect.x; - root_y_nw = new_rect.y; - - if (w != window->rect.width || - h != window->rect.height) - need_resize_client = TRUE; - - window->rect.width = w; - window->rect.height = h; - - if (window->frame) - { - int frame_size_dx, frame_size_dy; - int new_w, new_h; - - new_w = window->rect.width + borders.total.left + borders.total.right; - - if (window->shaded) - new_h = borders.total.top; - else - new_h = window->rect.height + borders.total.top + borders.total.bottom; - - frame_size_dx = new_w - window->frame->rect.width; - frame_size_dy = new_h - window->frame->rect.height; - - need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0); - - window->frame->rect.width = new_w; - window->frame->rect.height = new_h; - - meta_topic (META_DEBUG_GEOMETRY, - "Calculated frame size %dx%d\n", - window->frame->rect.width, - window->frame->rect.height); - } - - /* For nice effect, when growing the window we want to move/resize - * the frame first, when shrinking the window we want to move/resize - * the client first. If we grow one way and shrink the other, - * see which way we're moving "more" - * - * Mail from Owen subject "Suggestion: Gravity and resizing from the left" - * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html - * - * An annoying fact you need to know in this code is that StaticGravity - * does nothing if you _only_ resize or _only_ move the frame; - * it must move _and_ resize, otherwise you get NorthWestGravity - * behavior. The move and resize must actually occur, it is not - * enough to set CWX | CWWidth but pass in the current size/pos. - */ - - if (window->frame) - { - int new_x, new_y; - int frame_pos_dx, frame_pos_dy; - - /* Compute new frame coords */ - new_x = root_x_nw - borders.total.left; - new_y = root_y_nw - borders.total.top; - - frame_pos_dx = new_x - window->frame->rect.x; - frame_pos_dy = new_y - window->frame->rect.y; - - need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0); - - window->frame->rect.x = new_x; - window->frame->rect.y = new_y; - - /* If frame will both move and resize, then StaticGravity - * on the child window will kick in and implicitly move - * the child with respect to the frame. The implicit - * move will keep the child in the same place with - * respect to the root window. If frame only moves - * or only resizes, then the child will just move along - * with the frame. - */ - - /* window->rect.x, window->rect.y are relative to frame, - * remember they are the server coords - */ - - new_x = borders.total.left; - new_y = borders.total.top; - - if (need_resize_frame && need_move_frame && - static_gravity_works (window->display)) - { - /* static gravity kicks in because frame - * is both moved and resized - */ - /* when we move the frame by frame_pos_dx, frame_pos_dy the - * client will implicitly move relative to frame by the - * inverse delta. - * - * When moving client then frame, we move the client by the - * frame delta, to be canceled out by the implicit move by - * the inverse frame delta, resulting in a client at new_x, - * new_y. - * - * When moving frame then client, we move the client - * by the same delta as the frame, because the client - * was "left behind" by the frame - resulting in a client - * at new_x, new_y. - * - * In both cases we need to move the client window - * in all cases where we had to move the frame window. - */ - - client_move_x = new_x + frame_pos_dx; - client_move_y = new_y + frame_pos_dy; - - if (need_move_frame) - need_move_client = TRUE; - - use_static_gravity = TRUE; - } - else - { - client_move_x = new_x; - client_move_y = new_y; - - if (client_move_x != window->rect.x || - client_move_y != window->rect.y) - need_move_client = TRUE; - - use_static_gravity = FALSE; - } - - /* This is the final target position, but not necessarily what - * we pass to XConfigureWindow, due to StaticGravity implicit - * movement. - */ - window->rect.x = new_x; - window->rect.y = new_y; - } - else - { - if (root_x_nw != window->rect.x || - root_y_nw != window->rect.y) - need_move_client = TRUE; - - window->rect.x = root_x_nw; - window->rect.y = root_y_nw; - - client_move_x = window->rect.x; - client_move_y = window->rect.y; - - use_static_gravity = FALSE; - } - - /* If frame extents have changed, fill in other frame fields and - change frame's extents property. */ - if (window->frame && - (window->frame->child_x != borders.total.left || - window->frame->child_y != borders.total.top || - window->frame->right_width != borders.total.right || - window->frame->bottom_height != borders.total.bottom)) - { - window->frame->child_x = borders.total.left; - window->frame->child_y = borders.total.top; - window->frame->right_width = borders.total.right; - window->frame->bottom_height = borders.total.bottom; - - update_net_frame_extents (window); - } - - /* See ICCCM 4.1.5 for when to send ConfigureNotify */ - - need_configure_notify = FALSE; - - /* If this is a configure request and we change nothing, then we - * must send configure notify. - */ - if (is_configure_request && - !(need_move_client || need_move_frame || - need_resize_client || need_resize_frame || - window->border_width != 0)) - need_configure_notify = TRUE; - - /* We must send configure notify if we move but don't resize, since - * the client window may not get a real event - */ - if ((need_move_client || need_move_frame) && - !(need_resize_client || need_resize_frame)) - need_configure_notify = TRUE; - - /* MapRequest events with a PPosition or UPosition hint with a frame - * are moved by mutter without resizing; send a configure notify - * in such cases. See #322840. (Note that window->constructing is - * only true iff this call is due to a MapRequest, and when - * PPosition/UPosition hints aren't set, mutter seems to send a - * ConfigureNotify anyway due to the above code.) - */ - if (window->constructing && window->frame && - ((window->size_hints.flags & PPosition) || - (window->size_hints.flags & USPosition))) - need_configure_notify = TRUE; - - /* The rest of this function syncs our new size/pos with X as - * efficiently as possible - */ - - /* Normally, we configure the frame first depending on whether - * we grow the frame more than we shrink. The idea is to avoid - * messing up the window contents by having a temporary situation - * where the frame is smaller than the window. However, if we're - * cooperating with the client to create an atomic frame upate, - * and the window is redirected, then we should always update - * the frame first, since updating the frame will force a new - * backing pixmap to be allocated, and the old backing pixmap - * will be left undisturbed for us to paint to the screen until - * the client finishes redrawing. - */ - if (window->extended_sync_request_counter) - { - configure_frame_first = TRUE; - } - else - { - size_dx = w - window->rect.width; - size_dy = h - window->rect.height; - - configure_frame_first = size_dx + size_dy >= 0; - } - - if (use_static_gravity) - meta_window_set_gravity (window, StaticGravity); - - if (configure_frame_first && window->frame) - frame_shape_changed = meta_frame_sync_to_window (window->frame, - gravity, - need_move_frame, need_resize_frame); - - values.border_width = 0; - values.x = client_move_x; - values.y = client_move_y; - values.width = window->rect.width; - values.height = window->rect.height; - - mask = 0; - if (is_configure_request && window->border_width != 0) - mask |= CWBorderWidth; /* must force to 0 */ - if (need_move_client) - mask |= (CWX | CWY); - if (need_resize_client) - mask |= (CWWidth | CWHeight); - - if (mask != 0) + if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)) { - { - int newx, newy; - meta_window_get_position (window, &newx, &newy); - meta_topic (META_DEBUG_GEOMETRY, - "Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n", - newx, newy, - window->rect.width, window->rect.height, - mask & CWBorderWidth ? "true" : "false", - need_move_client ? "true" : "false", - need_resize_client ? "true" : "false"); - } - - meta_error_trap_push (window->display); - -#ifdef HAVE_XSYNC - if (window == window->display->grab_window && - meta_grab_op_is_resizing (window->display->grab_op) && - !window->disable_sync && - window->sync_request_counter != None && - window->sync_request_alarm != None && - window->sync_request_timeout_id == 0) - { - send_sync_request (window); - } -#endif - - XConfigureWindow (window->display->xdisplay, - window->xwindow, - mask, - &values); - - meta_error_trap_pop (window->display); + meta_window_constrain (window, + flags, + gravity, + &old_rect, + &new_rect); } - if (!configure_frame_first && window->frame) - frame_shape_changed = meta_frame_sync_to_window (window->frame, - gravity, - need_move_frame, need_resize_frame); - - /* Put gravity back to be nice to lesser window managers */ - if (use_static_gravity) - meta_window_set_gravity (window, NorthWestGravity); - - if (need_configure_notify) - send_configure_notify (window); + /* Do the protocol-specific move/resize logic */ + META_WINDOW_GET_CLASS (window)->move_resize_internal (window, gravity, requested_rect, new_rect, flags, &result); if (!window->placed && window->force_save_user_rect && !window->fullscreen) force_save_user_window_placement (window); else if (is_user_action) save_user_window_placement (window); - if (need_move_client || need_move_frame) + if (result & META_MOVE_RESIZE_RESULT_MOVED) g_signal_emit (window, window_signals[POSITION_CHANGED], 0); - if (need_resize_client || need_resize_frame) + if (result & META_MOVE_RESIZE_RESULT_RESIZED) g_signal_emit (window, window_signals[SIZE_CHANGED], 0); - if (need_move_frame || need_resize_frame || - need_move_client || need_resize_client || - did_placement) + if ((result & (META_MOVE_RESIZE_RESULT_MOVED | META_MOVE_RESIZE_RESULT_RESIZED)) != 0 || + did_placement || is_wayland_resize) { int newx, newy; meta_window_get_position (window, &newx, &newy); @@ -5202,7 +4334,7 @@ meta_window_move_resize_internal (MetaWindow *window, newx, newy, window->rect.width, window->rect.height, window->user_rect.x, window->user_rect.y, window->user_rect.width, window->user_rect.height); - if (window->display->compositor) + if (window->known_to_compositor) meta_compositor_sync_window_geometry (window->display->compositor, window, did_placement); @@ -5222,7 +4354,7 @@ meta_window_move_resize_internal (MetaWindow *window, * b) all constraints are obeyed by window->rect and frame->rect */ - if (frame_shape_changed && window->frame_bounds) + if ((result & META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED) && window->frame_bounds) { cairo_region_destroy (window->frame_bounds); window->frame_bounds = NULL; @@ -5263,6 +4395,38 @@ meta_window_resize (MetaWindow *window, x, y, w, h); } +/* + * meta_window_move_resize_wayland: + * + * Complete a resize operation from a wayland client. + * + */ +void +meta_window_move_resize_wayland (MetaWindow *window, + int width, + int height, + int dx, + int dy) +{ + int x, y; + MetaMoveResizeFlags flags; + + flags = META_IS_WAYLAND_RESIZE; + + meta_window_get_position (window, &x, &y); + x += dx; y += dy; + + if (x != window->expected_rect.x || y != window->expected_rect.y) + flags |= META_IS_MOVE_ACTION; + if (width != window->expected_rect.width || + height != window->expected_rect.height) + flags |= META_IS_RESIZE_ACTION; + + meta_window_move_resize_internal (window, flags, NorthWestGravity, + x, y, width, height); + save_user_window_placement (window); +} + /** * meta_window_move: * @window: a #MetaWindow @@ -5493,40 +4657,6 @@ idle_move_resize (gpointer data) return FALSE; } -/** - * meta_window_configure_notify: (skip) - * @window: a #MetaWindow - * @event: a #XConfigureEvent - * - * This is used to notify us of an unrequested configuration - * (only applicable to override redirect windows) - */ -void -meta_window_configure_notify (MetaWindow *window, - XConfigureEvent *event) -{ - g_assert (window->override_redirect); - g_assert (window->frame == NULL); - - window->rect.x = event->x; - window->rect.y = event->y; - window->rect.width = event->width; - window->rect.height = event->height; - meta_window_update_monitor (window); - - /* Whether an override-redirect window is considered fullscreen depends - * on its geometry. - */ - if (window->override_redirect) - meta_screen_queue_check_fullscreen (window->screen); - - if (!event->override_redirect && !event->send_event) - meta_warning ("Unhandled change of windows override redirect status\n"); - - if (window->display->compositor) - meta_compositor_sync_window_geometry (window->display->compositor, window, FALSE); -} - void meta_window_get_position (MetaWindow *window, int *x, @@ -5896,8 +5026,8 @@ get_modal_transient (MetaWindow *window) { MetaWindow *transient = tmp->data; - if (transient->xtransient_for == modal_transient->xwindow && - transient->wm_state_modal) + if (transient->transient_for == modal_transient && + transient->type == META_WINDOW_MODAL_DIALOG) { modal_transient = transient; tmp = windows; @@ -5962,69 +5092,7 @@ meta_window_focus (MetaWindow *window, return; } - /* For output-only or shaded windows, focus the frame. - * This seems to result in the client window getting key events - * though, so I don't know if it's icccm-compliant. - * - * Still, we have to do this or keynav breaks for these windows. - */ - if (window->frame && - (window->shaded || - !(window->input || window->take_focus))) - { - if (window->frame) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing frame of %s\n", window->desc); - meta_display_set_input_focus_window (window->display, - window, - TRUE, - timestamp); - } - } - else - { - if (window->input) - { - meta_topic (META_DEBUG_FOCUS, - "Setting input focus on %s since input = true\n", - window->desc); - meta_display_set_input_focus_window (window->display, - window, - FALSE, - timestamp); - } - - if (window->take_focus) - { - meta_topic (META_DEBUG_FOCUS, - "Sending WM_TAKE_FOCUS to %s since take_focus = true\n", - window->desc); - - if (!window->input) - { - /* The "Globally Active Input" window case, where the window - * doesn't want us to call XSetInputFocus on it, but does - * want us to send a WM_TAKE_FOCUS. - * - * Normally, we want to just leave the focus undisturbed until - * the window respnds to WM_TAKE_FOCUS, but if we're unmanaging - * the current focus window we *need* to move the focus away, so - * we focus the no_focus_window now (and set - * display->focus_window to that) before sending WM_TAKE_FOCUS. - */ - if (window->display->focus_window != NULL && - window->display->focus_window->unmanaging) - meta_display_focus_the_no_focus_window (window->display, - window->screen, - timestamp); - } - - meta_display_request_take_focus (window->display, - window, - timestamp); - } - } + META_WINDOW_GET_CLASS (window)->focus (window, timestamp); if (window->wm_state_demands_attention) meta_window_unset_demands_attention(window); @@ -6180,35 +5248,6 @@ meta_window_get_net_wm_desktop (MetaWindow *window) return meta_workspace_index (window->workspace); } -static void -update_net_frame_extents (MetaWindow *window) -{ - unsigned long data[4]; - MetaFrameBorders borders; - - meta_frame_calc_borders (window->frame, &borders); - /* Left */ - data[0] = borders.visible.left; - /* Right */ - data[1] = borders.visible.right; - /* Top */ - data[2] = borders.visible.top; - /* Bottom */ - data[3] = borders.visible.bottom; - - meta_topic (META_DEBUG_GEOMETRY, - "Setting _NET_FRAME_EXTENTS on managed window 0x%lx " - "to left = %lu, right = %lu, top = %lu, bottom = %lu\n", - window->xwindow, data[0], data[1], data[2], data[3]); - - meta_error_trap_push (window->display); - XChangeProperty (window->display->xdisplay, window->xwindow, - window->display->atom__NET_FRAME_EXTENTS, - XA_CARDINAL, - 32, PropModeReplace, (guchar*) data, 4); - meta_error_trap_pop (window->display); -} - void meta_window_set_current_workspace_hint (MetaWindow *window) { @@ -6326,42 +5365,6 @@ meta_window_lower (MetaWindow *window) } void -meta_window_send_icccm_message (MetaWindow *window, - Atom atom, - guint32 timestamp) -{ - /* This comment and code are from twm, copyright - * Open Group, Evans & Sutherland, etc. - */ - - /* - * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all - * client messages will have the following form: - * - * event type ClientMessage - * message type _XA_WM_PROTOCOLS - * window tmp->w - * format 32 - * data[0] message atom - * data[1] time stamp - */ - - XClientMessageEvent ev; - - ev.type = ClientMessage; - ev.window = window->xwindow; - ev.message_type = window->display->atom_WM_PROTOCOLS; - ev.format = 32; - ev.data.l[0] = atom; - ev.data.l[1] = timestamp; - - meta_error_trap_push (window->display); - XSendEvent (window->display->xdisplay, - window->xwindow, False, 0, (XEvent*) &ev); - meta_error_trap_pop (window->display); -} - -void meta_window_move_resize_request (MetaWindow *window, guint value_mask, int gravity, @@ -6526,97 +5529,6 @@ meta_window_move_resize_request (MetaWindow *window, save_user_window_placement (window); } -gboolean -meta_window_configure_request (MetaWindow *window, - XEvent *event) -{ - /* Note that x, y is the corner of the window border, - * and width, height is the size of the window inside - * its border, but that we always deny border requests - * and give windows a border of 0. But we save the - * requested border here. - */ - if (event->xconfigurerequest.value_mask & CWBorderWidth) - window->border_width = event->xconfigurerequest.border_width; - - meta_window_move_resize_request(window, - event->xconfigurerequest.value_mask, - window->size_hints.win_gravity, - event->xconfigurerequest.x, - event->xconfigurerequest.y, - event->xconfigurerequest.width, - event->xconfigurerequest.height); - - /* Handle stacking. We only handle raises/lowers, mostly because - * stack.c really can't deal with anything else. I guess we'll fix - * that if a client turns up that really requires it. Only a very - * few clients even require the raise/lower (and in fact all client - * attempts to deal with stacking order are essentially broken, - * since they have no idea what other clients are involved or how - * the stack looks). - * - * I'm pretty sure no interesting client uses TopIf, BottomIf, or - * Opposite anyway, so the only possible missing thing is - * Above/Below with a sibling set. For now we just pretend there's - * never a sibling set and always do the full raise/lower instead of - * the raise-just-above/below-sibling. - */ - if (event->xconfigurerequest.value_mask & CWStackMode) - { - MetaWindow *active_window; - active_window = window->display->focus_window; - if (meta_prefs_get_disable_workarounds ()) - { - meta_topic (META_DEBUG_STACK, - "%s sent an xconfigure stacking request; this is " - "broken behavior and the request is being ignored.\n", - window->desc); - } - else if (active_window && - !meta_window_same_application (window, active_window) && - !meta_window_same_client (window, active_window) && - XSERVER_TIME_IS_BEFORE (window->net_wm_user_time, - active_window->net_wm_user_time)) - { - meta_topic (META_DEBUG_STACK, - "Ignoring xconfigure stacking request from %s (with " - "user_time %u); currently active application is %s (with " - "user_time %u).\n", - window->desc, - window->net_wm_user_time, - active_window->desc, - active_window->net_wm_user_time); - if (event->xconfigurerequest.detail == Above) - meta_window_set_demands_attention(window); - } - else - { - switch (event->xconfigurerequest.detail) - { - case Above: - meta_window_raise (window); - break; - case Below: - meta_window_lower (window); - break; - case TopIf: - case BottomIf: - case Opposite: - break; - } - } - } - - return TRUE; -} - -gboolean -meta_window_property_notify (MetaWindow *window, - XEvent *event) -{ - return process_property_notify (window, &event->xproperty); -} - /* * Move window to the requested workspace; append controls whether new WS * should be created if one does not exist. @@ -6654,531 +5566,6 @@ meta_window_change_workspace_by_index (MetaWindow *window, } } -#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 -#define _NET_WM_MOVERESIZE_SIZE_TOP 1 -#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 -#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 -#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 -#define _NET_WM_MOVERESIZE_MOVE 8 -#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 -#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 -#define _NET_WM_MOVERESIZE_CANCEL 11 - -static int -query_pressed_buttons (MetaWindow *window) -{ - double x, y, query_root_x, query_root_y; - Window root, child; - XIButtonState buttons; - XIModifierState mods; - XIGroupState group; - int button = 0; - - meta_error_trap_push (window->display); - XIQueryPointer (window->display->xdisplay, - META_VIRTUAL_CORE_POINTER_ID, - window->xwindow, - &root, &child, - &query_root_x, &query_root_y, - &x, &y, - &buttons, &mods, &group); - - if (meta_error_trap_pop_with_return (window->display) != Success) - goto out; - - if (XIMaskIsSet (buttons.mask, Button1)) - button |= 1 << 1; - if (XIMaskIsSet (buttons.mask, Button2)) - button |= 1 << 2; - if (XIMaskIsSet (buttons.mask, Button3)) - button |= 1 << 3; - - free (buttons.mask); - - out: - return button; -} - -gboolean -meta_window_client_message (MetaWindow *window, - XEvent *event) -{ - MetaDisplay *display; - - display = window->display; - - if (window->override_redirect) - { - /* Don't warn here: we could warn on any of the messages below, - * but we might also receive other client messages that are - * part of protocols we don't know anything about. So, silently - * ignoring is simplest. - */ - return FALSE; - } - - if (event->xclient.message_type == - display->atom__NET_CLOSE_WINDOW) - { - guint32 timestamp; - - if (event->xclient.data.l[0] != 0) - timestamp = event->xclient.data.l[0]; - else - { - meta_warning ("Receiving a NET_CLOSE_WINDOW message for %s without " - "a timestamp! This means some buggy (outdated) " - "application is on the loose!\n", - window->desc); - timestamp = meta_display_get_current_time (window->display); - } - - meta_window_delete (window, timestamp); - - return TRUE; - } - else if (event->xclient.message_type == - display->atom__NET_WM_DESKTOP) - { - int space; - MetaWorkspace *workspace; - - space = event->xclient.data.l[0]; - - meta_verbose ("Request to move %s to workspace %d\n", - window->desc, space); - - workspace = - meta_screen_get_workspace_by_index (window->screen, - space); - - if (workspace) - { - if (window->on_all_workspaces_requested) - meta_window_unstick (window); - meta_window_change_workspace (window, workspace); - } - else if (space == (int) 0xFFFFFFFF) - { - meta_window_stick (window); - } - else - { - meta_verbose ("No such workspace %d for screen\n", space); - } - - meta_verbose ("Window %s now on_all_workspaces = %d\n", - window->desc, window->on_all_workspaces); - - return TRUE; - } - else if (event->xclient.message_type == - display->atom__NET_WM_STATE) - { - gulong action; - Atom first; - Atom second; - - action = event->xclient.data.l[0]; - first = event->xclient.data.l[1]; - second = event->xclient.data.l[2]; - - if (meta_is_verbose ()) - { - char *str1; - char *str2; - - meta_error_trap_push_with_return (display); - str1 = XGetAtomName (display->xdisplay, first); - if (meta_error_trap_pop_with_return (display) != Success) - str1 = NULL; - - meta_error_trap_push_with_return (display); - str2 = XGetAtomName (display->xdisplay, second); - if (meta_error_trap_pop_with_return (display) != Success) - str2 = NULL; - - meta_verbose ("Request to change _NET_WM_STATE action %lu atom1: %s atom2: %s\n", - action, - str1 ? str1 : "(unknown)", - str2 ? str2 : "(unknown)"); - - meta_XFree (str1); - meta_XFree (str2); - } - - if (first == display->atom__NET_WM_STATE_SHADED || - second == display->atom__NET_WM_STATE_SHADED) - { - gboolean shade; - guint32 timestamp; - - /* Stupid protocol has no timestamp; of course, shading - * sucks anyway so who really cares that we're forced to do - * a roundtrip here? - */ - timestamp = meta_display_get_current_time_roundtrip (window->display); - - shade = (action == _NET_WM_STATE_ADD || - (action == _NET_WM_STATE_TOGGLE && !window->shaded)); - if (shade && window->has_shade_func) - meta_window_shade (window, timestamp); - else - meta_window_unshade (window, timestamp); - } - - if (first == display->atom__NET_WM_STATE_FULLSCREEN || - second == display->atom__NET_WM_STATE_FULLSCREEN) - { - gboolean make_fullscreen; - - make_fullscreen = (action == _NET_WM_STATE_ADD || - (action == _NET_WM_STATE_TOGGLE && !window->fullscreen)); - if (make_fullscreen && window->has_fullscreen_func) - meta_window_make_fullscreen (window); - else - meta_window_unmake_fullscreen (window); - } - - if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || - second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || - first == display->atom__NET_WM_STATE_MAXIMIZED_VERT || - second == display->atom__NET_WM_STATE_MAXIMIZED_VERT) - { - gboolean max; - MetaMaximizeFlags directions = 0; - - max = (action == _NET_WM_STATE_ADD || - (action == _NET_WM_STATE_TOGGLE && - !window->maximized_horizontally)); - - if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || - second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ) - directions |= META_MAXIMIZE_HORIZONTAL; - - if (first == display->atom__NET_WM_STATE_MAXIMIZED_VERT || - second == display->atom__NET_WM_STATE_MAXIMIZED_VERT) - directions |= META_MAXIMIZE_VERTICAL; - - if (max && window->has_maximize_func) - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - meta_window_maximize (window, directions); - } - else - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - meta_window_unmaximize (window, directions); - } - } - - if (first == display->atom__NET_WM_STATE_MODAL || - second == display->atom__NET_WM_STATE_MODAL) - { - window->wm_state_modal = - (action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->wm_state_modal); - - recalc_window_type (window); - meta_window_queue(window, META_QUEUE_MOVE_RESIZE); - } - - if (first == display->atom__NET_WM_STATE_SKIP_PAGER || - second == display->atom__NET_WM_STATE_SKIP_PAGER) - { - window->wm_state_skip_pager = - (action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->skip_pager); - - recalc_window_features (window); - set_net_wm_state (window); - } - - if (first == display->atom__NET_WM_STATE_SKIP_TASKBAR || - second == display->atom__NET_WM_STATE_SKIP_TASKBAR) - { - window->wm_state_skip_taskbar = - (action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->skip_taskbar); - - recalc_window_features (window); - set_net_wm_state (window); - } - - if (first == display->atom__NET_WM_STATE_ABOVE || - second == display->atom__NET_WM_STATE_ABOVE) - { - meta_window_set_above(window, - (action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->wm_state_above)); - } - - if (first == display->atom__NET_WM_STATE_BELOW || - second == display->atom__NET_WM_STATE_BELOW) - { - window->wm_state_below = - (action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->wm_state_below); - - meta_window_update_layer (window); - set_net_wm_state (window); - } - - if (first == display->atom__NET_WM_STATE_DEMANDS_ATTENTION || - second == display->atom__NET_WM_STATE_DEMANDS_ATTENTION) - { - if ((action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention)) - meta_window_set_demands_attention (window); - else - meta_window_unset_demands_attention (window); - } - - if (first == display->atom__NET_WM_STATE_STICKY || - second == display->atom__NET_WM_STATE_STICKY) - { - if ((action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->on_all_workspaces_requested)) - meta_window_stick (window); - else - meta_window_unstick (window); - } - - return TRUE; - } - else if (event->xclient.message_type == - display->atom_WM_CHANGE_STATE) - { - meta_verbose ("WM_CHANGE_STATE client message, state: %ld\n", - event->xclient.data.l[0]); - if (event->xclient.data.l[0] == IconicState && - window->has_minimize_func) - meta_window_minimize (window); - - return TRUE; - } - else if (event->xclient.message_type == - display->atom__NET_WM_MOVERESIZE) - { - int x_root; - int y_root; - int action; - MetaGrabOp op; - int button; - guint32 timestamp; - - /* _NET_WM_MOVERESIZE messages are almost certainly going to come from - * clients when users click on the fake "frame" that the client has, - * thus we should also treat such messages as though it were a - * "frame action". - */ - gboolean const frame_action = TRUE; - - x_root = event->xclient.data.l[0]; - y_root = event->xclient.data.l[1]; - action = event->xclient.data.l[2]; - button = event->xclient.data.l[3]; - - /* FIXME: What a braindead protocol; no timestamp?!? */ - timestamp = meta_display_get_current_time_roundtrip (display); - meta_topic (META_DEBUG_WINDOW_OPS, - "Received _NET_WM_MOVERESIZE message on %s, %d,%d action = %d, button %d\n", - window->desc, - x_root, y_root, action, button); - - op = META_GRAB_OP_NONE; - switch (action) - { - case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: - op = META_GRAB_OP_RESIZING_NW; - break; - case _NET_WM_MOVERESIZE_SIZE_TOP: - op = META_GRAB_OP_RESIZING_N; - break; - case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT: - op = META_GRAB_OP_RESIZING_NE; - break; - case _NET_WM_MOVERESIZE_SIZE_RIGHT: - op = META_GRAB_OP_RESIZING_E; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT: - op = META_GRAB_OP_RESIZING_SE; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOM: - op = META_GRAB_OP_RESIZING_S; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: - op = META_GRAB_OP_RESIZING_SW; - break; - case _NET_WM_MOVERESIZE_SIZE_LEFT: - op = META_GRAB_OP_RESIZING_W; - break; - case _NET_WM_MOVERESIZE_MOVE: - op = META_GRAB_OP_MOVING; - break; - case _NET_WM_MOVERESIZE_SIZE_KEYBOARD: - op = META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN; - break; - case _NET_WM_MOVERESIZE_MOVE_KEYBOARD: - op = META_GRAB_OP_KEYBOARD_MOVING; - break; - case _NET_WM_MOVERESIZE_CANCEL: - /* handled below */ - break; - default: - break; - } - - if (action == _NET_WM_MOVERESIZE_CANCEL) - { - meta_display_end_grab_op (window->display, timestamp); - } - else if (op != META_GRAB_OP_NONE && - ((window->has_move_func && op == META_GRAB_OP_KEYBOARD_MOVING) || - (window->has_resize_func && op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN))) - { - meta_window_begin_grab_op (window, op, frame_action, timestamp); - } - else if (op != META_GRAB_OP_NONE && - ((window->has_move_func && op == META_GRAB_OP_MOVING) || - (window->has_resize_func && - (op != META_GRAB_OP_MOVING && - op != META_GRAB_OP_KEYBOARD_MOVING)))) - { - int button_mask; - - meta_topic (META_DEBUG_WINDOW_OPS, - "Beginning move/resize with button = %d\n", button); - meta_display_begin_grab_op (window->display, - window->screen, - window, - op, - FALSE, - frame_action, - button, 0, - timestamp, - x_root, - y_root); - - button_mask = query_pressed_buttons (window); - - if (button == 0) - { - /* - * the button SHOULD already be included in the message - */ - if ((button_mask & (1 << 1)) != 0) - button = 1; - else if ((button_mask & (1 << 2)) != 0) - button = 2; - else if ((button_mask & (1 << 3)) != 0) - button = 3; - - if (button != 0) - window->display->grab_button = button; - else - meta_display_end_grab_op (window->display, - timestamp); - } - else - { - /* There is a potential race here. If the user presses and - * releases their mouse button very fast, it's possible for - * both the ButtonPress and ButtonRelease to be sent to the - * client before it can get a chance to send _NET_WM_MOVERESIZE - * to us. When that happens, we'll become stuck in a grab - * state, as we haven't received a ButtonRelease to cancel the - * grab. - * - * We can solve this by querying after we take the explicit - * pointer grab -- if the button isn't pressed, we cancel the - * drag immediately. - */ - - if ((button_mask & (1 << button)) == 0) - meta_display_end_grab_op (window->display, timestamp); - } - } - - return TRUE; - } - else if (event->xclient.message_type == - display->atom__NET_MOVERESIZE_WINDOW) - { - int gravity; - guint value_mask; - - gravity = (event->xclient.data.l[0] & 0xff); - value_mask = (event->xclient.data.l[0] & 0xf00) >> 8; - /* source = (event->xclient.data.l[0] & 0xf000) >> 12; */ - - if (gravity == 0) - gravity = window->size_hints.win_gravity; - - meta_window_move_resize_request(window, - value_mask, - gravity, - event->xclient.data.l[1], /* x */ - event->xclient.data.l[2], /* y */ - event->xclient.data.l[3], /* width */ - event->xclient.data.l[4]); /* height */ - } - else if (event->xclient.message_type == - display->atom__NET_ACTIVE_WINDOW) - { - MetaClientType source_indication; - guint32 timestamp; - - meta_verbose ("_NET_ACTIVE_WINDOW request for window '%s', activating\n", - window->desc); - - source_indication = event->xclient.data.l[0]; - timestamp = event->xclient.data.l[1]; - - if (source_indication > META_CLIENT_TYPE_MAX_RECOGNIZED) - source_indication = META_CLIENT_TYPE_UNKNOWN; - - if (timestamp == 0) - { - /* Client using older EWMH _NET_ACTIVE_WINDOW without a timestamp */ - meta_warning ("Buggy client sent a _NET_ACTIVE_WINDOW message with a " - "timestamp of 0 for %s\n", - window->desc); - timestamp = meta_display_get_current_time (display); - } - - window_activate (window, timestamp, source_indication, NULL); - return TRUE; - } - else if (event->xclient.message_type == - display->atom__NET_WM_FULLSCREEN_MONITORS) - { - gulong top, bottom, left, right; - - meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n", - window->desc); - - top = meta_screen_xinerama_index_to_monitor_index (window->screen, - event->xclient.data.l[0]); - bottom = meta_screen_xinerama_index_to_monitor_index (window->screen, - event->xclient.data.l[1]); - left = meta_screen_xinerama_index_to_monitor_index (window->screen, - event->xclient.data.l[2]); - right = meta_screen_xinerama_index_to_monitor_index (window->screen, - event->xclient.data.l[3]); - /* source_indication = event->xclient.data.l[4]; */ - - meta_window_update_fullscreen_monitors (window, top, bottom, left, right); - } - - return FALSE; -} - static void meta_window_appears_focused_changed (MetaWindow *window) { @@ -7189,6 +5576,14 @@ meta_window_appears_focused_changed (MetaWindow *window) if (window->frame) meta_frame_queue_draw (window->frame); + + if (window->surface) + { + if (meta_window_appears_focused (window)) + meta_wayland_surface_activated (window->surface); + else + meta_wayland_surface_deactivated (window->surface); + } } /** @@ -7283,11 +5678,6 @@ meta_window_set_focused_internal (MetaWindow *window, if (window->frame) meta_frame_queue_draw (window->frame); - meta_error_trap_push (window->display); - XInstallColormap (window->display->xdisplay, - window->colormap); - meta_error_trap_pop (window->display); - /* move into FOCUSED_WINDOW layer */ meta_window_update_layer (window); @@ -7326,11 +5716,6 @@ meta_window_set_focused_internal (MetaWindow *window, if (!window->attached_focus_window) meta_window_appears_focused_changed (window); - meta_error_trap_push (window->display); - XUninstallColormap (window->display->xdisplay, - window->colormap); - meta_error_trap_pop (window->display); - /* move out of FOCUSED_WINDOW layer */ meta_window_update_layer (window); @@ -7341,86 +5726,6 @@ meta_window_set_focused_internal (MetaWindow *window, } } -static gboolean -process_property_notify (MetaWindow *window, - XPropertyEvent *event) -{ - Window xid = window->xwindow; - - if (meta_is_verbose ()) /* avoid looking up the name if we don't have to */ - { - char *property_name = XGetAtomName (window->display->xdisplay, - event->atom); - - meta_verbose ("Property notify on %s for %s\n", - window->desc, property_name); - XFree (property_name); - } - - if (event->atom == window->display->atom__NET_WM_USER_TIME && - window->user_time_window) - { - xid = window->user_time_window; - } - - meta_window_reload_property_from_xwindow (window, xid, event->atom, FALSE); - - return TRUE; -} - -static void -send_configure_notify (MetaWindow *window) -{ - XEvent event; - - /* from twm */ - - event.type = ConfigureNotify; - event.xconfigure.display = window->display->xdisplay; - event.xconfigure.event = window->xwindow; - event.xconfigure.window = window->xwindow; - event.xconfigure.x = window->rect.x - window->border_width; - event.xconfigure.y = window->rect.y - window->border_width; - if (window->frame) - { - if (window->withdrawn) - { - MetaFrameBorders borders; - /* We reparent the client window and put it to the position - * where the visible top-left of the frame window currently is. - */ - - meta_frame_calc_borders (window->frame, &borders); - - event.xconfigure.x = window->frame->rect.x + borders.invisible.left; - event.xconfigure.y = window->frame->rect.y + borders.invisible.top; - } - else - { - /* Need to be in root window coordinates */ - event.xconfigure.x += window->frame->rect.x; - event.xconfigure.y += window->frame->rect.y; - } - } - event.xconfigure.width = window->rect.width; - event.xconfigure.height = window->rect.height; - event.xconfigure.border_width = window->border_width; /* requested not actual */ - event.xconfigure.above = None; /* FIXME */ - event.xconfigure.override_redirect = False; - - meta_topic (META_DEBUG_GEOMETRY, - "Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d\n", - window->desc, - event.xconfigure.x, event.xconfigure.y, - event.xconfigure.width, event.xconfigure.height); - - meta_error_trap_push (window->display); - XSendEvent (window->display->xdisplay, - window->xwindow, - False, StructureNotifyMask, &event); - meta_error_trap_pop (window->display); -} - /** * meta_window_get_icon_geometry: * @window: a #MetaWindow @@ -7473,448 +5778,6 @@ meta_window_set_icon_geometry (MetaWindow *window, } } -static Window -read_client_leader (MetaDisplay *display, - Window xwindow) -{ - Window retval = None; - - meta_prop_get_window (display, xwindow, - display->atom_WM_CLIENT_LEADER, - &retval); - - return retval; -} - -typedef struct -{ - Window leader; -} ClientLeaderData; - -static gboolean -find_client_leader_func (MetaWindow *ancestor, - void *data) -{ - ClientLeaderData *d; - - d = data; - - d->leader = read_client_leader (ancestor->display, - ancestor->xwindow); - - /* keep going if no client leader found */ - return d->leader == None; -} - -static void -update_sm_hints (MetaWindow *window) -{ - Window leader; - - window->xclient_leader = None; - window->sm_client_id = NULL; - - /* If not on the current window, we can get the client - * leader from transient parents. If we find a client - * leader, we read the SM_CLIENT_ID from it. - */ - leader = read_client_leader (window->display, window->xwindow); - if (leader == None) - { - ClientLeaderData d; - d.leader = None; - meta_window_foreach_ancestor (window, find_client_leader_func, - &d); - leader = d.leader; - } - - if (leader != None) - { - char *str; - - window->xclient_leader = leader; - - if (meta_prop_get_latin1_string (window->display, leader, - window->display->atom_SM_CLIENT_ID, - &str)) - { - window->sm_client_id = g_strdup (str); - meta_XFree (str); - } - } - else - { - meta_verbose ("Didn't find a client leader for %s\n", window->desc); - - if (!meta_prefs_get_disable_workarounds ()) - { - /* Some broken apps (kdelibs fault?) set SM_CLIENT_ID on the app - * instead of the client leader - */ - char *str; - - str = NULL; - if (meta_prop_get_latin1_string (window->display, window->xwindow, - window->display->atom_SM_CLIENT_ID, - &str)) - { - if (window->sm_client_id == NULL) /* first time through */ - meta_warning (_("Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n"), - window->desc); - - window->sm_client_id = g_strdup (str); - meta_XFree (str); - } - } - } - - meta_verbose ("Window %s client leader: 0x%lx SM_CLIENT_ID: '%s'\n", - window->desc, window->xclient_leader, - window->sm_client_id ? window->sm_client_id : "none"); -} - -void -meta_window_update_role (MetaWindow *window) -{ - char *str; - - g_return_if_fail (!window->override_redirect); - - if (window->role) - g_free (window->role); - window->role = NULL; - - if (meta_prop_get_latin1_string (window->display, window->xwindow, - window->display->atom_WM_WINDOW_ROLE, - &str)) - { - window->role = g_strdup (str); - meta_XFree (str); - } - - meta_verbose ("Updated role of %s to '%s'\n", - window->desc, window->role ? window->role : "null"); -} - -void -meta_window_update_net_wm_type (MetaWindow *window) -{ - int n_atoms; - Atom *atoms; - int i; - - window->type_atom = None; - n_atoms = 0; - atoms = NULL; - - meta_prop_get_atom_list (window->display, window->xwindow, - window->display->atom__NET_WM_WINDOW_TYPE, - &atoms, &n_atoms); - - i = 0; - while (i < n_atoms) - { - /* We break as soon as we find one we recognize, - * supposed to prefer those near the front of the list - */ - if (atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DOCK || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_MENU || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG || - atoms[i] == - window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP || - atoms[i] == - window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_COMBO || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DND || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL) - { - window->type_atom = atoms[i]; - break; - } - - ++i; - } - - meta_XFree (atoms); - - if (meta_is_verbose ()) - { - char *str; - - str = NULL; - if (window->type_atom != None) - { - meta_error_trap_push (window->display); - str = XGetAtomName (window->display->xdisplay, window->type_atom); - meta_error_trap_pop (window->display); - } - - meta_verbose ("Window %s type atom %s\n", window->desc, - str ? str : "(none)"); - - if (str) - meta_XFree (str); - } - - meta_window_recalc_window_type (window); -} - -static void -meta_window_set_opaque_region (MetaWindow *window, - cairo_region_t *region) -{ - g_clear_pointer (&window->opaque_region, cairo_region_destroy); - - if (region != NULL) - window->opaque_region = cairo_region_reference (region); - - if (window->display->compositor) - meta_compositor_window_shape_changed (window->display->compositor, window); -} - -void -meta_window_update_opaque_region_x11 (MetaWindow *window) -{ - cairo_region_t *opaque_region = NULL; - gulong *region = NULL; - int nitems; - - if (meta_prop_get_cardinal_list (window->display, - window->xwindow, - window->display->atom__NET_WM_OPAQUE_REGION, - ®ion, &nitems)) - { - cairo_rectangle_int_t *rects; - int i, rect_index, nrects; - - if (nitems % 4 != 0) - { - meta_verbose ("_NET_WM_OPAQUE_REGION does not have a list of 4-tuples."); - goto out; - } - - /* empty region */ - if (nitems == 0) - goto out; - - nrects = nitems / 4; - - rects = g_new (cairo_rectangle_int_t, nrects); - - rect_index = 0; - i = 0; - while (i < nitems) - { - cairo_rectangle_int_t *rect = &rects[rect_index]; - - rect->x = region[i++]; - rect->y = region[i++]; - rect->width = region[i++]; - rect->height = region[i++]; - - rect_index++; - } - - opaque_region = cairo_region_create_rectangles (rects, nrects); - - g_free (rects); - } - - out: - meta_XFree (region); - - meta_window_set_opaque_region (window, opaque_region); - cairo_region_destroy (opaque_region); -} - -static cairo_region_t * -region_create_from_x_rectangles (const XRectangle *rects, - int n_rects) -{ - int i; - cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects); - - for (i = 0; i < n_rects; i ++) - { - cairo_rects[i].x = rects[i].x; - cairo_rects[i].y = rects[i].y; - cairo_rects[i].width = rects[i].width; - cairo_rects[i].height = rects[i].height; - } - - return cairo_region_create_rectangles (cairo_rects, n_rects); -} - -static void -meta_window_set_input_region (MetaWindow *window, - cairo_region_t *region) -{ - g_clear_pointer (&window->input_region, cairo_region_destroy); - - if (region != NULL) - window->input_region = cairo_region_reference (region); - - if (window->display->compositor) - meta_compositor_window_shape_changed (window->display->compositor, window); -} - -void -meta_window_update_input_region_x11 (MetaWindow *window) -{ - cairo_region_t *region = NULL; - - /* Decorated windows don't have an input region, because - we don't shape the frame to match the client windows - (so the events are blocked by the frame anyway) - */ - if (window->decorated) - { - if (window->input_region) - meta_window_set_input_region (window, NULL); - return; - } - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (window->display)) - { - /* Translate the set of XShape rectangles that we - * get from the X server to a cairo_region. */ - XRectangle *rects = NULL; - int n_rects, ordering; - - meta_error_trap_push (window->display); - rects = XShapeGetRectangles (window->display->xdisplay, - window->xwindow, - ShapeInput, - &n_rects, - &ordering); - meta_error_trap_pop (window->display); - - /* XXX: The x shape extension doesn't provide a way to only test if an - * input shape has been specified, so we have to query and throw away the - * rectangles. */ - if (rects) - { - if (n_rects > 1 || - (n_rects == 1 && - (rects[0].x != 0 || - rects[0].y != 0 || - rects[0].width != window->rect.width || - rects[0].height != window->rect.height))) - region = region_create_from_x_rectangles (rects, n_rects); - - XFree (rects); - } - } -#endif /* HAVE_SHAPE */ - - if (region != NULL) - { - cairo_rectangle_int_t client_area; - - client_area.x = 0; - client_area.y = 0; - client_area.width = window->rect.width; - client_area.height = window->rect.height; - - /* The shape we get back from the client may have coordinates - * outside of the frame. The X SHAPE Extension requires that - * the overall shape the client provides never exceeds the - * "bounding rectangle" of the window -- the shape that the - * window would have gotten if it was unshaped. In our case, - * this is simply the client area. - */ - cairo_region_intersect_rectangle (region, &client_area); - } - - meta_window_set_input_region (window, region); - cairo_region_destroy (region); -} - -static void -meta_window_set_shape_region (MetaWindow *window, - cairo_region_t *region) -{ - g_clear_pointer (&window->shape_region, cairo_region_destroy); - - if (region != NULL) - window->shape_region = cairo_region_reference (region); - - if (window->display->compositor) - meta_compositor_window_shape_changed (window->display->compositor, window); -} - -void -meta_window_update_shape_region_x11 (MetaWindow *window) -{ - cairo_region_t *region = NULL; - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (window->display)) - { - /* Translate the set of XShape rectangles that we - * get from the X server to a cairo_region. */ - XRectangle *rects = NULL; - int n_rects, ordering; - - int x_bounding, y_bounding, x_clip, y_clip; - unsigned w_bounding, h_bounding, w_clip, h_clip; - int bounding_shaped, clip_shaped; - - meta_error_trap_push (window->display); - XShapeQueryExtents (window->display->xdisplay, window->xwindow, - &bounding_shaped, &x_bounding, &y_bounding, - &w_bounding, &h_bounding, - &clip_shaped, &x_clip, &y_clip, - &w_clip, &h_clip); - - if (bounding_shaped) - { - rects = XShapeGetRectangles (window->display->xdisplay, - window->xwindow, - ShapeBounding, - &n_rects, - &ordering); - } - meta_error_trap_pop (window->display); - - if (rects) - { - region = region_create_from_x_rectangles (rects, n_rects); - XFree (rects); - } - } -#endif - - if (region != NULL) - { - cairo_rectangle_int_t client_area; - - client_area.x = 0; - client_area.y = 0; - client_area.width = window->rect.width; - client_area.height = window->rect.height; - - /* The shape we get back from the client may have coordinates - * outside of the frame. The X SHAPE Extension requires that - * the overall shape the client provides never exceeds the - * "bounding rectangle" of the window -- the shape that the - * window would have gotten if it was unshaped. In our case, - * this is simply the client area. - */ - cairo_region_intersect_rectangle (region, &client_area); - } - - meta_window_set_shape_region (window, region); - cairo_region_destroy (region); -} - static void redraw_icon (MetaWindow *window) { @@ -8207,154 +6070,48 @@ meta_window_update_struts (MetaWindow *window) } } -void -meta_window_recalc_window_type (MetaWindow *window) -{ - recalc_window_type (window); -} - static void -recalc_window_type (MetaWindow *window) -{ - MetaWindowType old_type; - - old_type = window->type; - - if (window->type_atom != None) - { - if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP) - window->type = META_WINDOW_DESKTOP; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK) - window->type = META_WINDOW_DOCK; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR) - window->type = META_WINDOW_TOOLBAR; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU) - window->type = META_WINDOW_MENU; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY) - window->type = META_WINDOW_UTILITY; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH) - window->type = META_WINDOW_SPLASHSCREEN; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG) - window->type = META_WINDOW_DIALOG; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL) - window->type = META_WINDOW_NORMAL; - /* The below are *typically* override-redirect windows, but the spec does - * not disallow using them for managed windows. - */ - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU) - window->type = META_WINDOW_DROPDOWN_MENU; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU) - window->type = META_WINDOW_POPUP_MENU; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP) - window->type = META_WINDOW_TOOLTIP; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION) - window->type = META_WINDOW_NOTIFICATION; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_COMBO) - window->type = META_WINDOW_COMBO; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DND) - window->type = META_WINDOW_DND; - else - { - char *atom_name; - - /* - * Fallback on a normal type, and print warning. Don't abort. - */ - window->type = META_WINDOW_NORMAL; +meta_window_type_changed (MetaWindow *window) +{ + gboolean old_decorated = window->decorated; + GObject *object = G_OBJECT (window); - meta_error_trap_push (window->display); - atom_name = XGetAtomName (window->display->xdisplay, - window->type_atom); - meta_error_trap_pop (window->display); + window->attached = meta_window_should_attach_to_parent (window); + meta_window_recalc_features (window); - meta_warning ("Unrecognized type atom [%s] set for %s \n", - atom_name ? atom_name : "unknown", - window->desc); + if (!window->override_redirect) + set_net_wm_state (window); - if (atom_name) - XFree (atom_name); - } - } - else if (window->xtransient_for != None) - { - window->type = META_WINDOW_DIALOG; - } + /* Update frame */ + if (window->decorated) + meta_window_ensure_frame (window); else - { - window->type = META_WINDOW_NORMAL; - } - - if (window->type == META_WINDOW_DIALOG && - window->wm_state_modal) - window->type = META_WINDOW_MODAL_DIALOG; - - /* We don't want to allow override-redirect windows to have decorated-window - * types since that's just confusing. - */ - if (window->override_redirect) - { - switch (window->type) - { - /* Decorated types */ - case META_WINDOW_NORMAL: - case META_WINDOW_DIALOG: - case META_WINDOW_MODAL_DIALOG: - case META_WINDOW_MENU: - case META_WINDOW_UTILITY: - window->type = META_WINDOW_OVERRIDE_OTHER; - break; - /* Undecorated types, normally not override-redirect */ - case META_WINDOW_DESKTOP: - case META_WINDOW_DOCK: - case META_WINDOW_TOOLBAR: - case META_WINDOW_SPLASHSCREEN: - /* Undecorated types, normally override-redirect types */ - case META_WINDOW_DROPDOWN_MENU: - case META_WINDOW_POPUP_MENU: - case META_WINDOW_TOOLTIP: - case META_WINDOW_NOTIFICATION: - case META_WINDOW_COMBO: - case META_WINDOW_DND: - /* To complete enum */ - case META_WINDOW_OVERRIDE_OTHER: - break; - } - } - - meta_verbose ("Calculated type %u for %s, old type %u\n", - window->type, window->desc, old_type); - - if (old_type != window->type) - { - gboolean old_decorated = window->decorated; - GObject *object = G_OBJECT (window); - - window->attached = meta_window_should_attach_to_parent (window); - recalc_window_features (window); + meta_window_destroy_frame (window); - if (!window->override_redirect) - set_net_wm_state (window); + /* update stacking constraints */ + meta_window_update_layer (window); - /* Update frame */ - if (window->decorated) - meta_window_ensure_frame (window); - else - meta_window_destroy_frame (window); + meta_window_grab_keys (window); - /* update stacking constraints */ - meta_window_update_layer (window); + g_object_freeze_notify (object); - meta_window_grab_keys (window); + if (old_decorated != window->decorated) + g_object_notify (object, "decorated"); - g_object_freeze_notify (object); + g_object_notify (object, "window-type"); - if (old_decorated != window->decorated) - g_object_notify (object, "decorated"); + g_object_thaw_notify (object); +} - g_object_notify (object, "window-type"); +void +meta_window_set_type (MetaWindow *window, + MetaWindowType type) +{ + if (window->type == type) + return; - g_object_thaw_notify (object); - } + window->type = type; + meta_window_type_changed (window); } void @@ -8435,14 +6192,60 @@ set_allowed_actions_hint (MetaWindow *window) #undef MAX_N_ACTIONS } -void -meta_window_recalc_features (MetaWindow *window) +static void +meta_window_get_default_skip_hints (MetaWindow *window, + gboolean *skip_taskbar_out, + gboolean *skip_pager_out) { - recalc_window_features (window); + META_WINDOW_GET_CLASS (window)->get_default_skip_hints (window, skip_taskbar_out, skip_pager_out); } static void -recalc_window_features (MetaWindow *window) +meta_window_recalc_skip_features (MetaWindow *window) +{ + switch (window->type) + { + /* Force skip taskbar/pager on these window types */ + case META_WINDOW_DESKTOP: + case META_WINDOW_DOCK: + case META_WINDOW_TOOLBAR: + case META_WINDOW_MENU: + case META_WINDOW_UTILITY: + case META_WINDOW_SPLASHSCREEN: + case META_WINDOW_DROPDOWN_MENU: + case META_WINDOW_POPUP_MENU: + case META_WINDOW_TOOLTIP: + case META_WINDOW_NOTIFICATION: + case META_WINDOW_COMBO: + case META_WINDOW_DND: + case META_WINDOW_OVERRIDE_OTHER: + window->skip_taskbar = TRUE; + window->skip_pager = TRUE; + break; + + case META_WINDOW_DIALOG: + case META_WINDOW_MODAL_DIALOG: + /* only skip taskbar if we have a real transient parent + (and ignore the application hints) */ + if (window->transient_for != NULL) + window->skip_taskbar = TRUE; + else + window->skip_taskbar = FALSE; + break; + + case META_WINDOW_NORMAL: + { + gboolean skip_taskbar_hint, skip_pager_hint; + meta_window_get_default_skip_hints (window, &skip_taskbar_hint, &skip_pager_hint); + window->skip_taskbar = skip_taskbar_hint; + window->skip_pager = skip_pager_hint; + } + break; + } +} + +void +meta_window_recalc_features (MetaWindow *window) { gboolean old_has_close_func; gboolean old_has_minimize_func; @@ -8461,7 +6264,10 @@ recalc_window_features (MetaWindow *window) old_skip_taskbar = window->skip_taskbar; /* Use MWM hints initially */ - window->decorated = window->mwm_decorated; + if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) + window->decorated = window->mwm_decorated; + else + window->decorated = FALSE; window->border_only = window->mwm_border_only; window->has_close_func = window->mwm_has_close_func; window->has_minimize_func = window->mwm_has_minimize_func; @@ -8484,7 +6290,7 @@ recalc_window_features (MetaWindow *window) * about these apps but make them work. */ - meta_warning (_("Window %s sets an MWM hint indicating it isn't resizable, but sets min size %d x %d and max size %d x %d; this doesn't make much sense.\n"), + meta_warning ("Window %s sets an MWM hint indicating it isn't resizable, but sets min size %d x %d and max size %d x %d; this doesn't make much sense.\n", window->desc, window->size_hints.min_width, window->size_hints.min_height, @@ -8589,49 +6395,7 @@ recalc_window_features (MetaWindow *window) if (!window->decorated || window->border_only) window->has_shade_func = FALSE; - window->skip_taskbar = FALSE; - window->skip_pager = FALSE; - - if (window->wm_state_skip_taskbar) - window->skip_taskbar = TRUE; - - if (window->wm_state_skip_pager) - window->skip_pager = TRUE; - - switch (window->type) - { - /* Force skip taskbar/pager on these window types */ - case META_WINDOW_DESKTOP: - case META_WINDOW_DOCK: - case META_WINDOW_TOOLBAR: - case META_WINDOW_MENU: - case META_WINDOW_UTILITY: - case META_WINDOW_SPLASHSCREEN: - case META_WINDOW_DROPDOWN_MENU: - case META_WINDOW_POPUP_MENU: - case META_WINDOW_TOOLTIP: - case META_WINDOW_NOTIFICATION: - case META_WINDOW_COMBO: - case META_WINDOW_DND: - case META_WINDOW_OVERRIDE_OTHER: - window->skip_taskbar = TRUE; - window->skip_pager = TRUE; - break; - - case META_WINDOW_DIALOG: - case META_WINDOW_MODAL_DIALOG: - /* only skip taskbar if we have a real transient parent - (and ignore the application hints) */ - if (window->xtransient_for != None && - window->xtransient_for != window->screen->xroot) - window->skip_taskbar = TRUE; - else - window->skip_taskbar = FALSE; - break; - - case META_WINDOW_NORMAL: - break; - } + meta_window_recalc_skip_features (window); meta_topic (META_DEBUG_WINDOW_OPS, "Window %s decorated = %d border_only = %d has_close = %d has_minimize = %d has_maximize = %d has_move = %d has_shade = %d skip_taskbar = %d skip_pager = %d\n", @@ -8650,10 +6414,9 @@ recalc_window_features (MetaWindow *window) g_object_notify (G_OBJECT (window), "skip-taskbar"); /* FIXME: - * Lame workaround for recalc_window_features - * being used overzealously. The fix is to - * only recalc_window_features when something - * has actually changed. + * Lame workaround for recalc_features being used overzealously. + * The fix is to only recalc_features when something has + * actually changed. */ if (window->constructing || old_has_close_func != window->has_close_func || @@ -9672,98 +7435,6 @@ update_resize (MetaWindow *window, g_get_current_time (&window->display->grab_last_moveresize_time); } -typedef struct -{ - Window window; - int count; - guint32 last_time; -} EventScannerData; - -static Bool -find_last_time_predicate (Display *display, - XEvent *ev, - XPointer arg) -{ - EventScannerData *esd = (void*) arg; - XIEvent *xev; - - if (ev->type != GenericEvent) - return False; - - /* We are peeking into events not yet handled by GDK, - * Allocate cookie events here so we can handle XI2. - * - * GDK will handle later these events, and eventually - * free the cookie data itself. - */ - XGetEventData (display, &ev->xcookie); - xev = (XIEvent *) ev->xcookie.data; - - if (xev->evtype != XI_Motion) - return False; - - if (esd->window != ((XIDeviceEvent *) xev)->event) - return False; - - esd->count += 1; - esd->last_time = xev->time; - - return False; -} - -static gboolean -check_use_this_motion_notify (MetaWindow *window, - XIDeviceEvent *xev) -{ - EventScannerData esd; - XEvent useless; - - /* This code is copied from Owen's GDK code. */ - - if (window->display->grab_motion_notify_time != 0) - { - /* == is really the right test, but I'm all for paranoia */ - if (window->display->grab_motion_notify_time <= - xev->time) - { - meta_topic (META_DEBUG_RESIZING, - "Arrived at event with time %u (waiting for %u), using it\n", - (unsigned int)xev->time, - window->display->grab_motion_notify_time); - window->display->grab_motion_notify_time = 0; - return TRUE; - } - else - return FALSE; /* haven't reached the saved timestamp yet */ - } - - esd.window = xev->event; - esd.count = 0; - esd.last_time = 0; - - /* "useless" isn't filled in because the predicate never returns True */ - XCheckIfEvent (window->display->xdisplay, - &useless, - find_last_time_predicate, - (XPointer) &esd); - - if (esd.count > 0) - meta_topic (META_DEBUG_RESIZING, - "Will skip %d motion events and use the event with time %u\n", - esd.count, (unsigned int) esd.last_time); - - if (esd.last_time == 0) - return TRUE; - else - { - /* Save this timestamp, and ignore all motion notify - * until we get to the one with this stamp. - */ - window->display->grab_motion_notify_time = esd.last_time; - return FALSE; - } -} - static void update_tile_mode (MetaWindow *window) { @@ -9781,6 +7452,15 @@ update_tile_mode (MetaWindow *window) } } +void +meta_window_update_resize (MetaWindow *window, + gboolean snap, + int x, int y, + gboolean force) +{ + update_resize (window, snap, x, y, force); +} + #ifdef HAVE_XSYNC void meta_window_update_sync_request_counter (MetaWindow *window, @@ -9835,18 +7515,24 @@ meta_window_update_sync_request_counter (MetaWindow *window, #endif /* HAVE_XSYNC */ void -meta_window_handle_mouse_grab_op_event (MetaWindow *window, - XIDeviceEvent *xev) +meta_window_handle_mouse_grab_op_event (MetaWindow *window, + const ClutterEvent *event) { - switch (xev->evtype) + gboolean is_window_root = (event->any.stage != NULL && + window && + window->screen && + CLUTTER_ACTOR (event->any.stage) == + meta_get_stage_for_screen (window->screen)); + + switch (event->type) { - case XI_ButtonRelease: - if (xev->detail == 1 || - xev->detail == meta_prefs_get_mouse_button_resize ()) + case CLUTTER_BUTTON_RELEASE: + if (event->button.button == 1 || + event->button.button == (unsigned int) meta_prefs_get_mouse_button_resize ()) { meta_display_check_threshold_reached (window->display, - xev->root_x, - xev->root_y); + event->button.x, + event->button.y); /* If the user was snap moving then ignore the button * release because they may have let go of shift before * releasing the mouse button and they almost certainly do @@ -9859,19 +7545,19 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window, { if (window->tile_mode != META_TILE_NONE) meta_window_tile (window); - else if (xev->root == window->screen->xroot) + else if (is_window_root) update_move (window, - xev->mods.effective & ShiftMask, - xev->root_x, - xev->root_y); + event->button.modifier_state & CLUTTER_SHIFT_MASK, + event->button.x, + event->button.y); } else if (meta_grab_op_is_resizing (window->display->grab_op)) { - if (xev->root == window->screen->xroot) + if (is_window_root) update_resize (window, - xev->mods.effective & ShiftMask, - xev->root_x, - xev->root_y, + event->button.modifier_state & CLUTTER_SHIFT_MASK, + event->button.x, + event->button.y, TRUE); /* If a tiled window has been dragged free with a @@ -9884,37 +7570,33 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window, update_tile_mode (window); } } - meta_display_end_grab_op (window->display, xev->time); + meta_display_end_grab_op (window->display, event->any.time); } break; - case XI_Motion: + case CLUTTER_MOTION: meta_display_check_threshold_reached (window->display, - xev->root_x, - xev->root_y); + event->motion.x, + event->motion.y); if (meta_grab_op_is_moving (window->display->grab_op)) { - if (xev->root == window->screen->xroot) + if (is_window_root) { - if (check_use_this_motion_notify (window, - xev)) - update_move (window, - xev->mods.effective & ShiftMask, - xev->root_x, - xev->root_y); + update_move (window, + event->button.modifier_state & CLUTTER_SHIFT_MASK, + event->motion.x, + event->motion.y); } } else if (meta_grab_op_is_resizing (window->display->grab_op)) { - if (xev->root == window->screen->xroot) + if (is_window_root) { - if (check_use_this_motion_notify (window, - xev)) - update_resize (window, - xev->mods.effective & ShiftMask, - xev->root_x, - xev->root_y, - FALSE); + update_resize (window, + event->button.modifier_state & CLUTTER_SHIFT_MASK, + event->motion.x, + event->motion.y, + FALSE); } } break; @@ -9924,26 +7606,6 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window, } } -void -meta_window_set_gravity (MetaWindow *window, - int gravity) -{ - XSetWindowAttributes attrs; - - meta_verbose ("Setting gravity of %s to %d\n", window->desc, gravity); - - attrs.win_gravity = gravity; - - meta_error_trap_push (window->display); - - XChangeWindowAttributes (window->display->xdisplay, - window->xwindow, - CWWinGravity, - &attrs); - - meta_error_trap_pop (window->display); -} - static void get_work_area_monitor (MetaWindow *window, MetaRectangle *area, @@ -10096,23 +7758,6 @@ meta_window_same_application (MetaWindow *window, group==other_group; } -/* Generally meta_window_same_application() is a better idea - * of "sameness", since it handles the case where multiple apps - * want to look like the same app or the same app wants to look - * like multiple apps, but in the case of workarounds for legacy - * applications (which likely aren't setting the group properly - * anyways), it may be desirable to check this as well. - */ -static gboolean -meta_window_same_client (MetaWindow *window, - MetaWindow *other_window) -{ - int resource_mask = window->display->xdisplay->resource_mask; - - return ((window->xwindow & ~resource_mask) == - (other_window->xwindow & ~resource_mask)); -} - /** * meta_window_is_client_decorated: * @@ -10122,13 +7767,23 @@ meta_window_same_client (MetaWindow *window, gboolean meta_window_is_client_decorated (MetaWindow *window) { - /* Currently the implementation here is hackish - - * has_custom_frame_extents() is set if _GTK_FRAME_EXTENTS is set - * to any value even 0. GTK+ always sets _GTK_FRAME_EXTENTS for - * client-side-decorated window, even if the value is 0 because - * the window is maxized and has no invisible borders or shadows. - */ - return window->has_custom_frame_extents; + if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) + { + /* Assume all Wayland clients draw decorations - not strictly + * true but good enough for current purposes. + */ + return TRUE; + } + else + { + /* Currently the implementation here is hackish - + * has_custom_frame_extents() is set if _GTK_FRAME_EXTENTS is set + * to any value even 0. GTK+ always sets _GTK_FRAME_EXTENTS for + * client-side-decorated window, even if the value is 0 because + * the window is maxized and has no invisible borders or shadows. + */ + return window->has_custom_frame_extents; + } } void @@ -10251,11 +7906,10 @@ meta_window_foreach_ancestor (MetaWindow *window, w = window; do { - if (w->xtransient_for == None || - w->transient_parent_is_root_window) + if (w->transient_for == NULL) break; - w = meta_display_lookup_x_window (w->display, w->xtransient_for); + w = w->transient_for; } while (w && (* func) (w, user_data)); } @@ -10384,7 +8038,7 @@ warp_grab_pointer (MetaWindow *window, *x = CLAMP (*x, 0, window->screen->rect.width-1); *y = CLAMP (*y, 0, window->screen->rect.height-1); - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); meta_topic (META_DEBUG_WINDOW_OPS, "Warping pointer to %d,%d with window at %d,%d\n", @@ -10606,9 +8260,8 @@ meta_window_set_user_time (MetaWindow *window, /* If this is a terminal, user interaction with it means the user likely * doesn't want to have focus transferred for now due to new windows. */ - if (meta_prefs_get_focus_new_windows () == - G_DESKTOP_FOCUS_NEW_WINDOWS_STRICT && - __window_is_terminal (window)) + if (meta_prefs_get_focus_new_windows () == G_DESKTOP_FOCUS_NEW_WINDOWS_STRICT && + window_is_terminal (window)) window->display->allow_terminal_deactivation = FALSE; } @@ -10848,23 +8501,6 @@ meta_window_get_window_type (MetaWindow *window) } /** - * meta_window_get_window_type_atom: (skip) - * @window: a #MetaWindow - * - * Gets the X atom from the _NET_WM_WINDOW_TYPE property used by the - * application to set the window type. (Note that this is constrained - * to be some value that Mutter recognizes - a completely unrecognized - * type atom will be returned as None.) - * - * Return value: the raw X atom for the window type, or None - */ -Atom -meta_window_get_window_type_atom (MetaWindow *window) -{ - return window->type_atom; -} - -/** * meta_window_get_workspace: * @window: a #MetaWindow * @@ -11078,7 +8714,9 @@ meta_window_get_transient_for (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), NULL); - if (window->xtransient_for) + if (window->transient_for) + return window->transient_for; + else if (window->xtransient_for) return meta_display_lookup_x_window (window->display, window->xtransient_for); else @@ -11086,25 +8724,6 @@ meta_window_get_transient_for (MetaWindow *window) } /** - * meta_window_get_transient_for_as_xid: - * @window: a #MetaWindow - * - * Returns the XID of the window that is pointed to by the - * WM_TRANSIENT_FOR hint on this window (see XGetTransientForHint() - * or XSetTransientForHint()). Metacity keeps transient windows above their - * parents. A typical usage of this hint is for a dialog that wants to stay - * above its associated window. - * - * Return value: (transfer none): the window this window is transient for, or - * None if the WM_TRANSIENT_FOR hint is unset. - */ -Window -meta_window_get_transient_for_as_xid (MetaWindow *window) -{ - return window->xtransient_for; -} - -/** * meta_window_get_pid: * @window: a #MetaWindow * @@ -11154,23 +8773,6 @@ meta_window_is_remote (MetaWindow *window) } /** - * meta_window_is_modal: - * @window: a #MetaWindow - * - * Queries whether the window is in a modal state as described by the - * _NET_WM_STATE protocol. - * - * Return value: (transfer none): TRUE if the window is in modal state. - */ -gboolean -meta_window_is_modal (MetaWindow *window) -{ - g_return_val_if_fail (META_IS_WINDOW (window), FALSE); - - return window->wm_state_modal; -} - -/** * meta_window_get_mutter_hints: * @window: a #MetaWindow * @@ -11403,10 +9005,126 @@ meta_window_compute_tile_match (MetaWindow *window) } } -Window -meta_window_get_toplevel_xwindow (MetaWindow *window) +void +meta_window_set_title (MetaWindow *window, + const char *title) { - return window->frame ? window->frame->xwindow : window->xwindow; + g_free (window->title); + window->title = g_strdup (title); + + if (window->frame) + meta_ui_set_frame_title (window->screen->ui, + window->frame->xwindow, + window->title); + + meta_window_update_desc (window); + + g_object_notify (G_OBJECT (window), "title"); +} + +void +meta_window_set_wm_class (MetaWindow *window, + const char *wm_class, + const char *wm_instance) +{ + g_free (window->res_class); + g_free (window->res_name); + + window->res_name = g_strdup (wm_instance); + window->res_class = g_strdup (wm_class); + + g_object_notify (G_OBJECT (window), "wm-class"); +} + +void +meta_window_set_gtk_dbus_properties (MetaWindow *window, + const char *application_id, + const char *unique_bus_name, + const char *appmenu_path, + const char *menubar_path, + const char *application_object_path, + const char *window_object_path) +{ + g_object_freeze_notify (G_OBJECT (window)); + + g_free (window->gtk_application_id); + window->gtk_application_id = g_strdup (application_id); + g_object_notify (G_OBJECT (window), "gtk-application-id"); + + g_free (window->gtk_unique_bus_name); + window->gtk_unique_bus_name = g_strdup (unique_bus_name); + g_object_notify (G_OBJECT (window), "gtk-unique-bus-name"); + + g_free (window->gtk_app_menu_object_path); + window->gtk_app_menu_object_path = g_strdup (appmenu_path); + g_object_notify (G_OBJECT (window), "gtk-app-menu-object-path"); + + g_free (window->gtk_menubar_object_path); + window->gtk_menubar_object_path = g_strdup (menubar_path); + g_object_notify (G_OBJECT (window), "gtk-menubar-object-path"); + + g_free (window->gtk_application_object_path); + window->gtk_application_object_path = g_strdup (application_object_path); + g_object_notify (G_OBJECT (window), "gtk-application-object-path"); + + g_free (window->gtk_window_object_path); + window->gtk_window_object_path = g_strdup (window_object_path); + g_object_notify (G_OBJECT (window), "gtk-window-object-path"); + + g_object_thaw_notify (G_OBJECT (window)); +} + +void +meta_window_set_transient_for (MetaWindow *window, + MetaWindow *parent) +{ + if (meta_window_appears_focused (window) && window->transient_for != None) + meta_window_propagate_focus_appearance (window, FALSE); + + /* may now be a dialog */ + if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) + meta_window_x11_recalc_window_type (window); + + if (!window->constructing) + { + /* If the window attaches, detaches, or changes attached + * parents, we need to destroy the MetaWindow and let a new one + * be created (which happens as a side effect of + * meta_window_unmanage()). The condition below is correct + * because we know window->transient_for has changed. + */ + if (window->attached || meta_window_should_attach_to_parent (window)) + { + guint32 timestamp; + + timestamp = meta_display_get_current_time_roundtrip (window->display); + meta_window_unmanage (window, timestamp); + return; + } + } + + /* update stacking constraints */ + if (!window->override_redirect) + meta_stack_update_transient (window->screen->stack, window); + + /* We know this won't create a reference cycle because we check for loops */ + g_clear_object (&window->transient_for); + window->transient_for = parent ? g_object_ref (parent) : NULL; + + /* possibly change its group. We treat being a window's transient as + * equivalent to making it your group leader, to work around shortcomings + * in programs such as xmms-- see #328211. + */ + if (window->xtransient_for != None && + window->xgroup_leader != None && + window->xtransient_for != window->xgroup_leader) + meta_window_group_leader_changed (window); + + if (!window->constructing && !window->override_redirect) + meta_window_queue (window, META_QUEUE_MOVE_RESIZE); + + if (meta_window_appears_focused (window) && window->transient_for != None) + meta_window_propagate_focus_appearance (window, TRUE); } void @@ -11415,8 +9133,211 @@ meta_window_set_opacity (MetaWindow *window, { window->opacity = opacity; - if (window->display->compositor) - meta_compositor_window_opacity_changed (window->display->compositor, window); + meta_compositor_window_opacity_changed (window->display->compositor, window); +} + +static void +reset_ignored_crossing_serials (MetaDisplay *display) +{ + int i; + + i = 0; + while (i < N_IGNORED_CROSSING_SERIALS) + { + display->ignored_crossing_serials[i] = 0; + ++i; + } + + display->ungrab_should_not_cause_focus_window = None; +} + +typedef struct +{ + MetaWindow *window; + int pointer_x; + int pointer_y; +} MetaFocusData; + +static void +mouse_mode_focus (MetaWindow *window, + guint32 timestamp) +{ + MetaDisplay *display = window->display; + + if (window->type != META_WINDOW_DESKTOP) + { + meta_topic (META_DEBUG_FOCUS, + "Focusing %s at time %u.\n", window->desc, timestamp); + + meta_window_focus (window, timestamp); + + if (meta_prefs_get_auto_raise ()) + meta_display_queue_autoraise_callback (display, window); + else + meta_topic (META_DEBUG_FOCUS, "Auto raise is disabled\n"); + } + else + { + /* In mouse focus mode, we defocus when the mouse *enters* + * the DESKTOP window, instead of defocusing on LeaveNotify. + * This is because having the mouse enter override-redirect + * child windows unfortunately causes LeaveNotify events that + * we can't distinguish from the mouse actually leaving the + * toplevel window as we expect. But, since we filter out + * EnterNotify events on override-redirect windows, this + * alternative mechanism works great. + */ + if (meta_prefs_get_focus_mode() == G_DESKTOP_FOCUS_MODE_MOUSE && + display->focus_window != NULL) + { + meta_topic (META_DEBUG_FOCUS, + "Unsetting focus from %s due to mouse entering " + "the DESKTOP window\n", + display->focus_window->desc); + meta_display_focus_the_no_focus_window (display, + window->screen, + timestamp); + } + } +} + +static gboolean +window_focus_on_pointer_rest_callback (gpointer data) +{ + MetaFocusData *focus_data = data; + MetaWindow *window = focus_data->window; + MetaDisplay *display = window->display; + MetaScreen *screen = window->screen; + int root_x, root_y; + guint32 timestamp; + ClutterActor *child; + + if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) + goto out; + + meta_cursor_tracker_get_pointer (screen->cursor_tracker, + &root_x, &root_y, NULL); + + if (root_x != focus_data->pointer_x || + root_y != focus_data->pointer_y) + { + focus_data->pointer_x = root_x; + focus_data->pointer_y = root_y; + return TRUE; + } + + child = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (clutter_stage_get_default ()), + CLUTTER_PICK_REACTIVE, root_x, root_y); + if (!META_IS_SURFACE_ACTOR (child)) + goto out; + + window = + meta_stack_get_default_focus_window_at_point (screen->stack, + screen->active_workspace, + NULL, root_x, root_y); + + if (window == NULL) + goto out; + + timestamp = meta_display_get_current_time_roundtrip (display); + mouse_mode_focus (window, timestamp); + + out: + display->focus_timeout_id = 0; + return FALSE; +} + +/* The interval, in milliseconds, we use in focus-follows-mouse + * mode to check whether the pointer has stopped moving after a + * crossing event. + */ +#define FOCUS_TIMEOUT_DELAY 25 + +static void +queue_focus_callback (MetaDisplay *display, + MetaWindow *window, + int pointer_x, + int pointer_y) +{ + MetaFocusData *focus_data; + + focus_data = g_new (MetaFocusData, 1); + focus_data->window = window; + focus_data->pointer_x = pointer_x; + focus_data->pointer_y = pointer_y; + + if (display->focus_timeout_id != 0) + g_source_remove (display->focus_timeout_id); + + display->focus_timeout_id = + g_timeout_add_full (G_PRIORITY_DEFAULT, + FOCUS_TIMEOUT_DELAY, + window_focus_on_pointer_rest_callback, + focus_data, + g_free); +} + +void +meta_window_handle_enter (MetaWindow *window, + guint32 timestamp, + guint root_x, + guint root_y) +{ + MetaDisplay *display = window->display; + + switch (meta_prefs_get_focus_mode ()) + { + case G_DESKTOP_FOCUS_MODE_SLOPPY: + case G_DESKTOP_FOCUS_MODE_MOUSE: + display->mouse_mode = TRUE; + if (window->type != META_WINDOW_DOCK) + { + if (meta_prefs_get_focus_change_on_pointer_rest()) + queue_focus_callback (display, window, root_x, root_y); + else + mouse_mode_focus (window, timestamp); + + /* stop ignoring stuff */ + reset_ignored_crossing_serials (display); + } + break; + case G_DESKTOP_FOCUS_MODE_CLICK: + break; + } +} + +void +meta_window_set_surface_mapped (MetaWindow *window, + gboolean surface_mapped) +{ + if (window->surface_mapped == (guint) surface_mapped) + return; + + window->surface_mapped = surface_mapped; + meta_window_queue (window, META_QUEUE_CALC_SHOWING); +} + +Window +meta_window_get_toplevel_xwindow (MetaWindow *window) +{ + return window->frame ? window->frame->xwindow : window->xwindow; +} + +void +meta_window_set_custom_frame_extents (MetaWindow *window, + GtkBorder *extents) +{ + if (extents) + { + window->has_custom_frame_extents = TRUE; + window->custom_frame_extents = *extents; + } + else + { + window->has_custom_frame_extents = FALSE; + } + + meta_window_queue (window, META_QUEUE_MOVE_RESIZE); } gboolean @@ -11466,3 +9387,17 @@ meta_window_allows_resize (MetaWindow *window) { return META_WINDOW_ALLOWS_RESIZE (window); } + +void +meta_window_set_urgent (MetaWindow *window, + gboolean urgent) +{ + if (window->urgent == urgent) + return; + + window->urgent = urgent; + g_object_notify (G_OBJECT (window), "urgent"); + + if (urgent) + g_signal_emit_by_name (window->display, "window-marked-urgent", window); +} diff --git a/src/core/workspace.c b/src/core/workspace.c index f1e2527..ca87c0b 100644 --- a/src/core/workspace.c +++ b/src/core/workspace.c @@ -665,7 +665,7 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace, meta_screen_free_workspace_layout (&layout1); meta_screen_free_workspace_layout (&layout2); - meta_compositor_switch_workspace (comp, screen, old, workspace, direction); + meta_compositor_switch_workspace (comp, old, workspace, direction); /* This needs to be done after telling the compositor we are switching * workspaces since focusing a window will cause it to be immediately diff --git a/src/libmutter-wayland.pc.in b/src/libmutter-wayland.pc.in new file mode 100644 index 0000000..6537c4f --- /dev/null +++ b/src/libmutter-wayland.pc.in @@ -0,0 +1,18 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +girdir=@libdir@/mutter-wayland +typelibdir=@libdir@/mutter-wayland + +mutter_major_version=@MUTTER_MAJOR_VERSION@ +mutter_minor_version=@MUTTER_MINOR_VERSION@ +mutter_micro_version=@MUTTER_MICRO_VERSION@ +mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@ + +Name: libmutter-wayland +Description: Mutter window manager library (Wayland branch) +Requires: gsettings-desktop-schemas gtk+-3.0 @CLUTTER_PACKAGE@ x11 wayland-server +Version: @VERSION@ +Libs: -L${libdir} -lmutter-wayland +Cflags: -I${includedir}/mutter-wayland -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version} diff --git a/src/libmutter.pc.in b/src/libmutter.pc.in deleted file mode 100644 index 1f819af..0000000 --- a/src/libmutter.pc.in +++ /dev/null @@ -1,18 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -girdir=@libdir@/mutter -typelibdir=@libdir@/mutter - -mutter_major_version=@MUTTER_MAJOR_VERSION@ -mutter_minor_version=@MUTTER_MINOR_VERSION@ -mutter_micro_version=@MUTTER_MICRO_VERSION@ -mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@ - -Name: libmutter -Description: Mutter window manager library -Requires: gsettings-desktop-schemas gtk+-3.0 @CLUTTER_PACKAGE@ x11 -Version: @VERSION@ -Libs: -L${libdir} -lmutter -Cflags: -I${includedir}/mutter -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version} diff --git a/src/meta/atomnames.h b/src/meta/atomnames.h index 0fb31be..46e1a66 100644 --- a/src/meta/atomnames.h +++ b/src/meta/atomnames.h @@ -79,7 +79,9 @@ item(TIMESTAMP) item(VERSION) item(ATOM_PAIR) item(Backlight) +item(_XKB_RULES_NAMES) item(hotplug_mode_update) +item(WL_SURFACE_ID) /* Oddities: These are used, and we need atoms for them, * but when we need all _NET_WM hints (i.e. when we're making @@ -90,7 +92,6 @@ item(hotplug_mode_update) item(_NET_WM_SYNC_REQUEST) item(_NET_WM_SYNC_REQUEST_COUNTER) item(_NET_WM_VISIBLE_NAME) -item(_NET_WM_VISIBLE_ICON_NAME) item(_NET_SUPPORTING_WM_CHECK) /* But I suppose it's quite reasonable not to advertise using @@ -131,7 +132,6 @@ item(_NET_CLIENT_LIST) item(_NET_CLIENT_LIST_STACKING) item(_NET_WM_STATE_SKIP_TASKBAR) item(_NET_WM_STATE_SKIP_PAGER) -item(_NET_WM_ICON_NAME) item(_NET_WM_ICON) item(_NET_WM_ICON_GEOMETRY) item(_NET_WM_MOVERESIZE) diff --git a/src/meta/common.h b/src/meta/common.h index 583cc6e..6ae1d89 100644 --- a/src/meta/common.h +++ b/src/meta/common.h @@ -29,6 +29,7 @@ #include <X11/Xlib.h> #include <X11/extensions/XInput.h> #include <X11/extensions/XInput2.h> +#include <clutter/clutter.h> #include <glib.h> #include <gtk/gtk.h> @@ -162,13 +163,6 @@ typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu, * @META_GRAB_OP_KEYBOARD_RESIZING_NE: Resizing NE with keyboard * @META_GRAB_OP_KEYBOARD_RESIZING_SW: Resizing SW with keyboard * @META_GRAB_OP_KEYBOARD_RESIZING_NW: Resizing NS with keyboard - * @META_GRAB_OP_KEYBOARD_TABBING_NORMAL: Tabbing - * @META_GRAB_OP_KEYBOARD_TABBING_DOCK: Tabbing through docks - * @META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL: Escaping - * @META_GRAB_OP_KEYBOARD_ESCAPING_DOCK: Escaping through docks - * @META_GRAB_OP_KEYBOARD_ESCAPING_GROUP: Escaping through groups - * @META_GRAB_OP_KEYBOARD_TABBING_GROUP: Tabbing through groups - * @META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING: Switch to another workspace * @META_GRAB_OP_CLICKING_MINIMIZE: Clicked minimize button * @META_GRAB_OP_CLICKING_MAXIMIZE: Clicked maximize button * @META_GRAB_OP_CLICKING_UNMAXIMIZE: Clicked unmaximize button @@ -227,7 +221,10 @@ typedef enum META_GRAB_OP_CLICKING_UNSTICK, /* Special grab op when the compositor asked for a grab */ - META_GRAB_OP_COMPOSITOR + META_GRAB_OP_COMPOSITOR, + + /* For when a client takes a popup grab */ + META_GRAB_OP_WAYLAND_CLIENT, } MetaGrabOp; /** diff --git a/src/meta/compositor.h b/src/meta/compositor.h index d1be47e..57be80a 100644 --- a/src/meta/compositor.h +++ b/src/meta/compositor.h @@ -57,22 +57,21 @@ typedef enum MetaCompositor *meta_compositor_new (MetaDisplay *display); void meta_compositor_destroy (MetaCompositor *compositor); -void meta_compositor_manage_screen (MetaCompositor *compositor, - MetaScreen *screen); -void meta_compositor_unmanage_screen (MetaCompositor *compositor, - MetaScreen *screen); +void meta_compositor_manage (MetaCompositor *compositor); +void meta_compositor_unmanage (MetaCompositor *compositor); void meta_compositor_window_shape_changed (MetaCompositor *compositor, MetaWindow *window); void meta_compositor_window_opacity_changed (MetaCompositor *compositor, MetaWindow *window); +void meta_compositor_window_surface_changed (MetaCompositor *compositor, + MetaWindow *window); gboolean meta_compositor_process_event (MetaCompositor *compositor, XEvent *event, MetaWindow *window); gboolean meta_compositor_filter_keybinding (MetaCompositor *compositor, - MetaScreen *screen, MetaKeyBinding *binding); void meta_compositor_add_window (MetaCompositor *compositor, @@ -86,7 +85,6 @@ void meta_compositor_hide_window (MetaCompositor *compositor, MetaWindow *window, MetaCompEffect effect); void meta_compositor_switch_workspace (MetaCompositor *compositor, - MetaScreen *screen, MetaWorkspace *from, MetaWorkspace *to, MetaMotionDirection direction); @@ -111,10 +109,8 @@ void meta_compositor_queue_frame_drawn (MetaCompositor *compositor, gboolean no_delay_frame); void meta_compositor_sync_stack (MetaCompositor *compositor, - MetaScreen *screen, GList *stack); void meta_compositor_sync_screen_size (MetaCompositor *compositor, - MetaScreen *screen, guint width, guint height); @@ -122,11 +118,9 @@ void meta_compositor_flash_screen (MetaCompositor *compositor, MetaScreen *screen); void meta_compositor_show_tile_preview (MetaCompositor *compositor, - MetaScreen *screen, MetaWindow *window, MetaRectangle *tile_rect, int tile_monitor_number); -void meta_compositor_hide_tile_preview (MetaCompositor *compositor, - MetaScreen *screen); +void meta_compositor_hide_tile_preview (MetaCompositor *compositor); #endif /* META_COMPOSITOR_H */ diff --git a/src/meta/display.h b/src/meta/display.h index 60e9ab1..694d7e9 100644 --- a/src/meta/display.h +++ b/src/meta/display.h @@ -73,12 +73,9 @@ int meta_display_get_xinput_opcode (MetaDisplay *display); gboolean meta_display_supports_extended_barriers (MetaDisplay *display); Display *meta_display_get_xdisplay (MetaDisplay *display); MetaCompositor *meta_display_get_compositor (MetaDisplay *display); -GSList *meta_display_get_screens (MetaDisplay *display); gboolean meta_display_has_shape (MetaDisplay *display); -MetaScreen *meta_display_screen_for_root (MetaDisplay *display, - Window xroot); MetaWindow *meta_display_get_focus_window (MetaDisplay *display); gboolean meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display, @@ -95,8 +92,6 @@ guint32 meta_display_get_last_user_time (MetaDisplay *display); guint32 meta_display_get_current_time (MetaDisplay *display); guint32 meta_display_get_current_time_roundtrip (MetaDisplay *display); -unsigned int meta_display_get_ignored_modifier_mask (MetaDisplay *display); - GList* meta_display_get_tab_list (MetaDisplay *display, MetaTabList type, MetaScreen *screen, @@ -104,14 +99,12 @@ GList* meta_display_get_tab_list (MetaDisplay *display, MetaWindow* meta_display_get_tab_next (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace, MetaWindow *window, gboolean backward); MetaWindow* meta_display_get_tab_current (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace); gboolean meta_display_begin_grab_op (MetaDisplay *display, @@ -163,10 +156,6 @@ void meta_display_set_input_focus_window (MetaDisplay *display, gboolean focus_frame, guint32 timestamp); -void meta_display_request_take_focus (MetaDisplay *display, - MetaWindow *window, - guint32 timestamp); - /* meta_display_focus_the_no_focus_window is called when the * designated no_focus_window should be focused, but is otherwise the * same as meta_display_set_input_focus_window @@ -178,8 +167,6 @@ void meta_display_focus_the_no_focus_window (MetaDisplay *display, GSList *meta_display_sort_windows_by_stacking (MetaDisplay *display, GSList *windows); -Window meta_display_get_leader_window (MetaDisplay *display); - void meta_display_add_ignored_crossing_serial (MetaDisplay *display, unsigned long serial); diff --git a/src/meta/errors.h b/src/meta/errors.h index d2aa27b..36bd9b7 100644 --- a/src/meta/errors.h +++ b/src/meta/errors.h @@ -30,7 +30,6 @@ void meta_error_trap_push (MetaDisplay *display); void meta_error_trap_pop (MetaDisplay *display); -void meta_error_trap_push_with_return (MetaDisplay *display); /* returns X error code, or 0 for no error */ int meta_error_trap_pop_with_return (MetaDisplay *display); diff --git a/src/meta/main.h b/src/meta/main.h index 35eb73d..82f05a0 100644 --- a/src/meta/main.h +++ b/src/meta/main.h @@ -28,6 +28,7 @@ GOptionContext *meta_get_option_context (void); void meta_init (void); int meta_run (void); void meta_register_with_session (void); +gboolean meta_activate_session (void); /* Actually defined in meta-backend.c */ gboolean meta_get_replace_current_wm (void); /* Actually defined in util.c */ void meta_set_wm_name (const char *wm_name); diff --git a/src/meta/meta-background.h b/src/meta/meta-background.h index c171df3..a861600 100644 --- a/src/meta/meta-background.h +++ b/src/meta/meta-background.h @@ -91,7 +91,6 @@ void meta_background_load_gradient (MetaBackground *self, ClutterColor *second_color); void meta_background_load_color (MetaBackground *self, ClutterColor *color); -void meta_background_load_still_frame (MetaBackground *self); void meta_background_load_file_async (MetaBackground *self, const char *filename, GDesktopBackgroundStyle style, diff --git a/src/meta/meta-plugin.h b/src/meta/meta-plugin.h index cef7853..983db7a 100644 --- a/src/meta/meta-plugin.h +++ b/src/meta/meta-plugin.h @@ -254,9 +254,6 @@ struct _MetaPluginInfo GType meta_plugin_get_type (void); -gboolean meta_plugin_running (MetaPlugin *plugin); -gboolean meta_plugin_debug_mode (MetaPlugin *plugin); - const MetaPluginInfo * meta_plugin_get_info (MetaPlugin *plugin); /** @@ -408,8 +405,7 @@ meta_plugin_end_modal (MetaPlugin *plugin, MetaScreen *meta_plugin_get_screen (MetaPlugin *plugin); -void -_meta_plugin_effect_started (MetaPlugin *plugin); +void _meta_plugin_set_compositor (MetaPlugin *plugin, MetaCompositor *compositor); /* XXX: Putting this in here so it's in the public header. */ void meta_plugin_manager_set_plugin_type (GType gtype); diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h index b0870bf..80b23f2 100644 --- a/src/meta/meta-shaped-texture.h +++ b/src/meta/meta-shaped-texture.h @@ -75,9 +75,6 @@ CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex); void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, CoglTexture *mask_texture); -void meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex, - cairo_region_t *shape_region); - void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex, cairo_region_t *opaque_region); diff --git a/src/meta/prefs.h b/src/meta/prefs.h index 49d5076..677110a 100644 --- a/src/meta/prefs.h +++ b/src/meta/prefs.h @@ -376,17 +376,17 @@ typedef enum * @display: a #MetaDisplay * @screen: a #MetaScreen * @window: a #MetaWindow - * @event: (type gpointer): a #XIDeviceEvent + * @event: (type gpointer): a #ClutterKeyEvent * @binding: a #MetaKeyBinding * @user_data: data passed to the function * */ -typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer user_data); +typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer user_data); GType meta_key_binding_get_type (void); diff --git a/src/meta/screen.h b/src/meta/screen.h index 6e0cde7..4c3c52e 100644 --- a/src/meta/screen.h +++ b/src/meta/screen.h @@ -44,12 +44,6 @@ void meta_screen_get_size (MetaScreen *screen, int *width, int *height); -gpointer meta_screen_get_compositor_data (MetaScreen *screen); -void meta_screen_set_compositor_data (MetaScreen *screen, - gpointer info); - -MetaScreen *meta_screen_for_x_screen (Screen *xscreen); - void meta_screen_set_cm_selection (MetaScreen *screen); void meta_screen_unset_cm_selection (MetaScreen *screen); diff --git a/src/meta/util.h b/src/meta/util.h index 9328a26..4644de5 100644 --- a/src/meta/util.h +++ b/src/meta/util.h @@ -31,6 +31,7 @@ gboolean meta_is_verbose (void); gboolean meta_is_debugging (void); gboolean meta_is_syncing (void); +gboolean meta_is_wayland_compositor (void); void meta_debug_spew_real (const char *format, ...) G_GNUC_PRINTF (1, 2); diff --git a/src/meta/window.h b/src/meta/window.h index 671060f..3677790 100644 --- a/src/meta/window.h +++ b/src/meta/window.h @@ -81,6 +81,16 @@ typedef enum META_MAXIMIZE_BOTH = (1 << 0 | 1 << 1), } MetaMaximizeFlags; +/** + * MetaWindowClientType: + * @META_WINDOW_CLIENT_TYPE_WAYLAND: A Wayland based window + * @META_WINDOW_CLIENT_TYPE_X11: An X11 based window + */ +typedef enum { + META_WINDOW_CLIENT_TYPE_WAYLAND, + META_WINDOW_CLIENT_TYPE_X11 +} MetaWindowClientType; + #define META_TYPE_WINDOW (meta_window_get_type ()) #define META_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW, MetaWindow)) #define META_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW, MetaWindowClass)) @@ -115,7 +125,6 @@ MetaScreen *meta_window_get_screen (MetaWindow *window); MetaDisplay *meta_window_get_display (MetaWindow *window); Window meta_window_get_xwindow (MetaWindow *window); MetaWindowType meta_window_get_window_type (MetaWindow *window); -Atom meta_window_get_window_type_atom (MetaWindow *window); MetaWorkspace *meta_window_get_workspace (MetaWindow *window); int meta_window_get_monitor (MetaWindow *window); gboolean meta_window_is_on_all_workspaces (MetaWindow *window); @@ -155,7 +164,6 @@ void meta_window_change_workspace (MetaWindow *window, MetaWorkspace *workspace); GObject *meta_window_get_compositor_private (MetaWindow *window); void meta_window_set_compositor_private (MetaWindow *window, GObject *priv); -void meta_window_configure_notify (MetaWindow *window, XConfigureEvent *event); const char *meta_window_get_role (MetaWindow *window); MetaStackLayer meta_window_get_layer (MetaWindow *window); MetaWindow* meta_window_find_root_ancestor (MetaWindow *window); @@ -195,7 +203,6 @@ void meta_window_raise (MetaWindow *window); void meta_window_lower (MetaWindow *window); const char *meta_window_get_title (MetaWindow *window); MetaWindow *meta_window_get_transient_for (MetaWindow *window); -Window meta_window_get_transient_for_as_xid (MetaWindow *window); void meta_window_delete (MetaWindow *window, guint32 timestamp); guint meta_window_get_stable_sequence (MetaWindow *window); @@ -203,7 +210,6 @@ guint32 meta_window_get_user_time (MetaWindow *window); int meta_window_get_pid (MetaWindow *window); const char *meta_window_get_client_machine (MetaWindow *window); gboolean meta_window_is_remote (MetaWindow *window); -gboolean meta_window_is_modal (MetaWindow *window); gboolean meta_window_is_attached_dialog (MetaWindow *window); const char *meta_window_get_mutter_hints (MetaWindow *window); diff --git a/src/mutter-plugins.pc.in b/src/mutter-plugins.pc.in deleted file mode 100644 index 5d42232..0000000 --- a/src/mutter-plugins.pc.in +++ /dev/null @@ -1,17 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -plugindir=@MUTTER_PLUGIN_DIR@ -libgnome_serverdir=@libexecdir@ -mutter_major_version=@MUTTER_MAJOR_VERSION@ -mutter_minor_version=@MUTTER_MINOR_VERSION@ -mutter_micro_version=@MUTTER_MICRO_VERSION@ -mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@ - -Name: mutter-plugins -Description: Dev parameters for mutter plugins -Requires: @CLUTTER_PACKAGE@ -Version: @VERSION@ -Libs: @CLUTTER_LIBS@ -Cflags: @CLUTTER_CFLAGS@ -DWITH_CLUTTER -I${includedir}/mutter/mutter-private -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version} -DMUTTER_PLUGIN_DIR=\"${plugindir}\" diff --git a/src/mutter.desktop.in b/src/mutter-wayland.desktop.in index 3bfb88d..9f21316 100644 --- a/src/mutter.desktop.in +++ b/src/mutter-wayland.desktop.in @@ -1,7 +1,7 @@ [Desktop Entry] Type=Application -_Name=Mutter -Exec=mutter +_Name=Mutter (wayland compositor) +Exec=mutter-launch -- mutter --wayland --display-server NoDisplay=true # name of loadable control center module X-GNOME-WMSettingsModule=metacity @@ -12,6 +12,5 @@ X-GnomeWMSettingsLibrary=metacity X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=mutter X-GNOME-Bugzilla-Component=general -X-GNOME-Autostart-Phase=WindowManager -X-GNOME-Provides=windowmanager +X-GNOME-Autostart-Phase=DisplayServer X-GNOME-Autostart-Notify=true diff --git a/src/mutter-wm.desktop.in b/src/mutter-wm.desktop.in deleted file mode 100644 index 2b60c7e..0000000 --- a/src/mutter-wm.desktop.in +++ /dev/null @@ -1,20 +0,0 @@ -[Desktop Entry] -Type=Application -_Name=Mutter -Exec=mutter -# name of loadable control center module -X-GNOME-WMSettingsModule=metacity -# name we put on the WM spec check window -X-GNOME-WMName=Mutter -# back compat only -X-GnomeWMSettingsLibrary=metacity -X-GNOME-Bugzilla-Bugzilla=GNOME -X-GNOME-Bugzilla-Product=mutter -X-GNOME-Bugzilla-Component=general -X-GNOME-Autostart-Phase=WindowManager -X-GNOME-Provides=windowmanager -X-GNOME-Autostart-Notify=true - -[Window Manager] -SessionManaged=true - diff --git a/src/xrandr.xml b/src/org.gnome.Mutter.DisplayConfig.xml index 06449c3..06449c3 100644 --- a/src/xrandr.xml +++ b/src/org.gnome.Mutter.DisplayConfig.xml diff --git a/src/idle-monitor.xml b/src/org.gnome.Mutter.IdleMonitor.xml index 34a26dd..34a26dd 100644 --- a/src/idle-monitor.xml +++ b/src/org.gnome.Mutter.IdleMonitor.xml diff --git a/src/org.gnome.mutter.wayland.gschema.xml.in b/src/org.gnome.mutter.wayland.gschema.xml.in new file mode 100644 index 0000000..4bb5c1d --- /dev/null +++ b/src/org.gnome.mutter.wayland.gschema.xml.in @@ -0,0 +1,33 @@ +<schemalist> + <schema id="org.gnome.mutter.wayland.keybindings" path="/org/gnome/mutter/wayland/keybindings/" + gettext-domain="@GETTEXT_DOMAIN@"> + <key name="switch-to-session-1" type="as"> + <default><![CDATA[['<Primary><Alt>F1']]]></default> + <_summary>Switch to VT 1</_summary> + </key> + <key name="switch-to-session-2" type="as"> + <default><![CDATA[['<Primary><Alt>F2']]]></default> + <_summary>Switch to VT 2</_summary> + </key> + <key name="switch-to-session-3" type="as"> + <default><![CDATA[['<Primary><Alt>F3']]]></default> + <_summary>Switch to VT 3</_summary> + </key> + <key name="switch-to-session-4" type="as"> + <default><![CDATA[['<Primary><Alt>F4']]]></default> + <_summary>Switch to VT 4</_summary> + </key> + <key name="switch-to-session-5" type="as"> + <default><![CDATA[['<Primary><Alt>F5']]]></default> + <_summary>Switch to VT 5</_summary> + </key> + <key name="switch-to-session-6" type="as"> + <default><![CDATA[['<Primary><Alt>F6']]]></default> + <_summary>Switch to VT 6</_summary> + </key> + <key name="switch-to-session-7" type="as"> + <default><![CDATA[['<Primary><Alt>F7']]]></default> + <_summary>Switch to VT 7</_summary> + </key> + </schema> +</schemalist> diff --git a/src/run-mutter.sh b/src/run-mutter.sh deleted file mode 100755 index b64834f..0000000 --- a/src/run-mutter.sh +++ /dev/null @@ -1,109 +0,0 @@ -#! /bin/bash - -if test -z "$XNEST_DISPLAY"; then - XNEST_DISPLAY=:8 -fi - -if test -z "$CLIENT_DISPLAY"; then - CLIENT_DISPLAY=:8 -fi - -if test -z "$MUTTER_DISPLAY"; then - export MUTTER_DISPLAY=$CLIENT_DISPLAY -fi - -if test -z "$SCREENS"; then - SCREENS=1 -fi - -MAX_SCREEN=`echo $SCREENS-1 | bc` - -if test "$DEBUG" = none; then - DEBUG= -elif test -z "$DEBUG"; then - DEBUG= -fi - -if test -z "$CLIENTS"; then - CLIENTS=0 -fi - -if test -z "$SM_CLIENTS"; then - SM_CLIENTS=0 -fi - -if test -n "$EVIL_TEST"; then - TEST_CLIENT='./wm-tester/wm-tester --evil' -fi - -if test -n "$ICON_TEST"; then - TEST_CLIENT='./wm-tester/wm-tester --icon-windows' -fi - -if test -n "$DEMO_TEST"; then - TEST_CLIENT='./tools/mutter-window-demo' -fi - -if test -n "$XINERAMA"; then - XINERAMA_FLAGS='+xinerama' -fi - -export EF_ALLOW_MALLOC_0=1 - -if test -z "$ONLY_WM"; then - echo "Launching Xnest" - Xnest -ac $XNEST_DISPLAY -scrns $SCREENS -geometry 640x480 -bw 15 $XINERAMA_FLAGS & - ## usleep 800000 - sleep 1 - - if test -n "$XMON_DIR"; then - echo "Launching xmond" - $XMON_DIR/xmonui | $XMON_DIR/xmond -server localhost:$XNEST_DISPLAY & - sleep 1 - fi - - if test -n "$XSCOPE_DIR"; then - ## xscope doesn't like to die when it should, it backgrounds itself - killall -9 xscope - killall -9 xscope - echo "Launching xscope" - DISPLAY= $XSCOPE_DIR/xscope -o1 -i28 > xscoped-replies.txt & - export MUTTER_DISPLAY=localhost:28 - sleep 1 - fi - - echo "Launching clients" - if test -n "$TEST_CLIENT"; then - for I in `seq 0 $MAX_SCREEN`; do - DISPLAY=$CLIENT_DISPLAY.$I $TEST_CLIENT & - done - fi - - if test $CLIENTS != 0; then - for I in `seq 1 $CLIENTS`; do - echo "Launching xterm $I" - DISPLAY=$CLIENT_DISPLAY xterm -geometry 25x15 & - done - fi - - if test $SM_CLIENTS != 0; then - for I in `seq 1 $SM_CLIENTS`; do - echo "Launching gnome-terminal $I" - DISPLAY=$CLIENT_DISPLAY gnome-terminal --geometry 25x15 & - done - fi - - if test -e ~/.Xmodmap; then - DISPLAY=$CLIENT_DISPLAY xmodmap ~/.Xmodmap - fi - - usleep 50000 - - for I in `seq 0 $MAX_SCREEN`; do - DISPLAY=$CLIENT_DISPLAY.$I xsetroot -solid royalblue3 - done -fi - -if test -z "$ONLY_SETUP"; then - MUTTER_VERBOSE=1 MUTTER_USE_LOGFILE=1 MUTTER_DEBUG_BUTTON_GRABS=1 exec $DEBUG ./mutter $OPTIONS -fi diff --git a/src/ui/ui.c b/src/ui/ui.c index c890288..a4b8f91 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -32,11 +32,6 @@ #include <stdlib.h> #include <cairo-xlib.h> -static void meta_ui_accelerator_parse (const char *accel, - guint *keysym, - guint *keycode, - GdkModifierType *keymask); - struct _MetaUI { Display *xdisplay; @@ -54,6 +49,8 @@ struct _MetaUI void meta_ui_init (void) { + gdk_set_allowed_backends ("x11"); + if (!gtk_init_check (NULL, NULL)) meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL)); @@ -241,58 +238,17 @@ maybe_redirect_mouse_event (XEvent *xevent) return TRUE; } -typedef struct _EventFunc EventFunc; - -struct _EventFunc -{ - MetaEventFunc func; - gpointer data; -}; - -static EventFunc *ef = NULL; - static GdkFilterReturn -filter_func (GdkXEvent *xevent, - GdkEvent *event, - gpointer data) +ui_filter_func (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) { - g_return_val_if_fail (ef != NULL, GDK_FILTER_CONTINUE); - - if ((* ef->func) (xevent, ef->data) || - maybe_redirect_mouse_event (xevent)) + if (maybe_redirect_mouse_event (xevent)) return GDK_FILTER_REMOVE; else return GDK_FILTER_CONTINUE; } -void -meta_ui_add_event_func (Display *xdisplay, - MetaEventFunc func, - gpointer data) -{ - g_return_if_fail (ef == NULL); - - ef = g_new (EventFunc, 1); - ef->func = func; - ef->data = data; - - gdk_window_add_filter (NULL, filter_func, ef); -} - -/* removal is by data due to proxy function */ -void -meta_ui_remove_event_func (Display *xdisplay, - MetaEventFunc func, - gpointer data) -{ - g_return_if_fail (ef != NULL); - - gdk_window_remove_filter (NULL, filter_func, ef); - - g_free (ef); - ef = NULL; -} - MetaUI* meta_ui_new (Display *xdisplay, Screen *screen) @@ -316,6 +272,8 @@ meta_ui_new (Display *xdisplay, */ gtk_widget_show (GTK_WIDGET (ui->frames)); + gdk_window_add_filter (NULL, ui_filter_func, NULL); + g_object_set_data (G_OBJECT (gdisplay), "meta-ui", ui); return ui; @@ -331,6 +289,8 @@ meta_ui_free (MetaUI *ui) gdisplay = gdk_x11_lookup_xdisplay (ui->xdisplay); g_object_set_data (G_OBJECT (gdisplay), "meta-ui", NULL); + gdk_window_remove_filter (NULL, ui_filter_func, NULL); + g_free (ui); } @@ -700,38 +660,6 @@ meta_ui_window_should_not_cause_focus (Display *xdisplay, return FALSE; } -char* -meta_text_property_to_utf8 (Display *xdisplay, - const XTextProperty *prop) -{ - GdkDisplay *display; - char **list; - int count; - char *retval; - - list = NULL; - - display = gdk_x11_lookup_xdisplay (xdisplay); - count = gdk_text_property_to_utf8_list_for_display (display, - gdk_x11_xatom_to_atom_for_display (display, prop->encoding), - prop->format, - prop->value, - prop->nitems, - &list); - - if (count == 0) - retval = NULL; - else - { - retval = list[0]; - list[0] = g_strdup (""); /* something to free */ - } - - g_strfreev (list); - - return retval; -} - void meta_ui_theme_get_frame_borders (MetaUI *ui, MetaFrameType type, @@ -797,196 +725,6 @@ meta_ui_have_a_theme (void) return meta_theme_get_current () != NULL; } -static void -meta_ui_accelerator_parse (const char *accel, - guint *keysym, - guint *keycode, - GdkModifierType *keymask) -{ - const char *above_tab; - - if (accel[0] == '0' && accel[1] == 'x') - { - *keysym = 0; - *keycode = (guint) strtoul (accel, NULL, 16); - *keymask = 0; - - return; - } - - /* The key name 'Above_Tab' is special - it's not an actual keysym name, - * but rather refers to the key above the tab key. In order to use - * the GDK parsing for modifiers in combination with it, we substitute - * it with 'Tab' temporarily before calling gtk_accelerator_parse(). - */ -#define is_word_character(c) (g_ascii_isalnum(c) || ((c) == '_')) -#define ABOVE_TAB "Above_Tab" -#define ABOVE_TAB_LEN 9 - - above_tab = strstr (accel, ABOVE_TAB); - if (above_tab && - (above_tab == accel || !is_word_character (above_tab[-1])) && - !is_word_character (above_tab[ABOVE_TAB_LEN])) - { - char *before = g_strndup (accel, above_tab - accel); - char *after = g_strdup (above_tab + ABOVE_TAB_LEN); - char *replaced = g_strconcat (before, "Tab", after, NULL); - - gtk_accelerator_parse (replaced, NULL, keymask); - - g_free (before); - g_free (after); - g_free (replaced); - - *keysym = META_KEY_ABOVE_TAB; - return; - } - -#undef is_word_character -#undef ABOVE_TAB -#undef ABOVE_TAB_LEN - - gtk_accelerator_parse (accel, keysym, keymask); -} - -gboolean -meta_ui_parse_accelerator (const char *accel, - unsigned int *keysym, - unsigned int *keycode, - MetaVirtualModifier *mask) -{ - GdkModifierType gdk_mask = 0; - guint gdk_sym = 0; - guint gdk_code = 0; - - *keysym = 0; - *keycode = 0; - *mask = 0; - - if (!accel[0] || strcmp (accel, "disabled") == 0) - return TRUE; - - meta_ui_accelerator_parse (accel, &gdk_sym, &gdk_code, &gdk_mask); - if (gdk_mask == 0 && gdk_sym == 0 && gdk_code == 0) - return FALSE; - - if (gdk_sym == None && gdk_code == 0) - return FALSE; - - if (gdk_mask & GDK_RELEASE_MASK) /* we don't allow this */ - return FALSE; - - *keysym = gdk_sym; - *keycode = gdk_code; - - if (gdk_mask & GDK_SHIFT_MASK) - *mask |= META_VIRTUAL_SHIFT_MASK; - if (gdk_mask & GDK_CONTROL_MASK) - *mask |= META_VIRTUAL_CONTROL_MASK; - if (gdk_mask & GDK_MOD1_MASK) - *mask |= META_VIRTUAL_ALT_MASK; - if (gdk_mask & GDK_MOD2_MASK) - *mask |= META_VIRTUAL_MOD2_MASK; - if (gdk_mask & GDK_MOD3_MASK) - *mask |= META_VIRTUAL_MOD3_MASK; - if (gdk_mask & GDK_MOD4_MASK) - *mask |= META_VIRTUAL_MOD4_MASK; - if (gdk_mask & GDK_MOD5_MASK) - *mask |= META_VIRTUAL_MOD5_MASK; - if (gdk_mask & GDK_SUPER_MASK) - *mask |= META_VIRTUAL_SUPER_MASK; - if (gdk_mask & GDK_HYPER_MASK) - *mask |= META_VIRTUAL_HYPER_MASK; - if (gdk_mask & GDK_META_MASK) - *mask |= META_VIRTUAL_META_MASK; - - return TRUE; -} - -/* Caller responsible for freeing return string of meta_ui_accelerator_name! */ -gchar* -meta_ui_accelerator_name (unsigned int keysym, - MetaVirtualModifier mask) -{ - GdkModifierType mods = 0; - - if (keysym == 0 && mask == 0) - { - return g_strdup ("disabled"); - } - - if (mask & META_VIRTUAL_SHIFT_MASK) - mods |= GDK_SHIFT_MASK; - if (mask & META_VIRTUAL_CONTROL_MASK) - mods |= GDK_CONTROL_MASK; - if (mask & META_VIRTUAL_ALT_MASK) - mods |= GDK_MOD1_MASK; - if (mask & META_VIRTUAL_MOD2_MASK) - mods |= GDK_MOD2_MASK; - if (mask & META_VIRTUAL_MOD3_MASK) - mods |= GDK_MOD3_MASK; - if (mask & META_VIRTUAL_MOD4_MASK) - mods |= GDK_MOD4_MASK; - if (mask & META_VIRTUAL_MOD5_MASK) - mods |= GDK_MOD5_MASK; - if (mask & META_VIRTUAL_SUPER_MASK) - mods |= GDK_SUPER_MASK; - if (mask & META_VIRTUAL_HYPER_MASK) - mods |= GDK_HYPER_MASK; - if (mask & META_VIRTUAL_META_MASK) - mods |= GDK_META_MASK; - - return gtk_accelerator_name (keysym, mods); - -} - -gboolean -meta_ui_parse_modifier (const char *accel, - MetaVirtualModifier *mask) -{ - GdkModifierType gdk_mask = 0; - guint gdk_sym = 0; - guint gdk_code = 0; - - *mask = 0; - - if (accel == NULL || !accel[0] || strcmp (accel, "disabled") == 0) - return TRUE; - - meta_ui_accelerator_parse (accel, &gdk_sym, &gdk_code, &gdk_mask); - if (gdk_mask == 0 && gdk_sym == 0 && gdk_code == 0) - return FALSE; - - if (gdk_sym != None || gdk_code != 0) - return FALSE; - - if (gdk_mask & GDK_RELEASE_MASK) /* we don't allow this */ - return FALSE; - - if (gdk_mask & GDK_SHIFT_MASK) - *mask |= META_VIRTUAL_SHIFT_MASK; - if (gdk_mask & GDK_CONTROL_MASK) - *mask |= META_VIRTUAL_CONTROL_MASK; - if (gdk_mask & GDK_MOD1_MASK) - *mask |= META_VIRTUAL_ALT_MASK; - if (gdk_mask & GDK_MOD2_MASK) - *mask |= META_VIRTUAL_MOD2_MASK; - if (gdk_mask & GDK_MOD3_MASK) - *mask |= META_VIRTUAL_MOD3_MASK; - if (gdk_mask & GDK_MOD4_MASK) - *mask |= META_VIRTUAL_MOD4_MASK; - if (gdk_mask & GDK_MOD5_MASK) - *mask |= META_VIRTUAL_MOD5_MASK; - if (gdk_mask & GDK_SUPER_MASK) - *mask |= META_VIRTUAL_SUPER_MASK; - if (gdk_mask & GDK_HYPER_MASK) - *mask |= META_VIRTUAL_HYPER_MASK; - if (gdk_mask & GDK_META_MASK) - *mask |= META_VIRTUAL_META_MASK; - - return TRUE; -} - gboolean meta_ui_window_is_widget (MetaUI *ui, Window xwindow) diff --git a/src/ui/ui.h b/src/ui/ui.h index ca52f4c..56e19fc 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -46,13 +46,6 @@ Display* meta_ui_get_display (void); gint meta_ui_get_screen_number (void); -void meta_ui_add_event_func (Display *xdisplay, - MetaEventFunc func, - gpointer data); -void meta_ui_remove_event_func (Display *xdisplay, - MetaEventFunc func, - gpointer data); - MetaUI* meta_ui_new (Display *xdisplay, Screen *screen); void meta_ui_free (MetaUI *ui); @@ -149,28 +142,9 @@ GdkPixbuf* meta_ui_get_default_mini_icon (MetaUI *ui); gboolean meta_ui_window_should_not_cause_focus (Display *xdisplay, Window xwindow); -char* meta_text_property_to_utf8 (Display *xdisplay, - const XTextProperty *prop); - void meta_ui_set_current_theme (const char *name); gboolean meta_ui_have_a_theme (void); -/* Not a real key symbol but means "key above the tab key"; this is - * used as the default keybinding for cycle_group. - * 0x2xxxxxxx is a range not used by GDK or X. the remaining digits are - * randomly chosen */ -#define META_KEY_ABOVE_TAB 0x2f7259c9 - -gboolean meta_ui_parse_accelerator (const char *accel, - unsigned int *keysym, - unsigned int *keycode, - MetaVirtualModifier *mask); -gboolean meta_ui_parse_modifier (const char *accel, - MetaVirtualModifier *mask); - -/* Caller responsible for freeing return string of meta_ui_accelerator_name! */ -gchar* meta_ui_accelerator_name (unsigned int keysym, - MetaVirtualModifier mask); gboolean meta_ui_window_is_widget (MetaUI *ui, Window xwindow); diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c new file mode 100644 index 0000000..c454761 --- /dev/null +++ b/src/wayland/meta-wayland-data-device.c @@ -0,0 +1,548 @@ +/* + * Copyright © 2011 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* The file is based on src/data-device.c from Weston */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> +#include <glib.h> + +#include "meta-wayland-data-device.h" +#include "meta-wayland-seat.h" +#include "meta-wayland-pointer.h" +#include "meta-wayland-private.h" + +static void +data_offer_accept (struct wl_client *client, + struct wl_resource *resource, + guint32 serial, + const char *mime_type) +{ + MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource); + + /* FIXME: Check that client is currently focused by the input + * device that is currently dragging this data source. Should + * this be a wl_data_device request? */ + + if (offer->source) + wl_data_source_send_target (offer->source->resource, mime_type); +} + +static void +data_offer_receive (struct wl_client *client, struct wl_resource *resource, + const char *mime_type, int32_t fd) +{ + MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource); + + if (offer->source) + wl_data_source_send_send (offer->source->resource, mime_type, fd); + + close (fd); +} + +static void +data_offer_destroy (struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct wl_data_offer_interface data_offer_interface = { + data_offer_accept, + data_offer_receive, + data_offer_destroy, +}; + +static void +destroy_data_offer (struct wl_resource *resource) +{ + MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource); + + if (offer->source) + wl_list_remove (&offer->source_destroy_listener.link); + + g_slice_free (MetaWaylandDataOffer, offer); +} + +static void +destroy_offer_data_source (struct wl_listener *listener, void *data) +{ + MetaWaylandDataOffer *offer; + + offer = wl_container_of (listener, offer, source_destroy_listener); + + offer->source = NULL; +} + +static struct wl_resource * +meta_wayland_data_source_send_offer (MetaWaylandDataSource *source, + struct wl_resource *target) +{ + MetaWaylandDataOffer *offer = g_slice_new0 (MetaWaylandDataOffer); + char **p; + + offer->source = source; + offer->source_destroy_listener.notify = destroy_offer_data_source; + + offer->resource = wl_resource_create (wl_resource_get_client (target), + &wl_data_offer_interface, + MIN (META_WL_DATA_OFFER_VERSION, + wl_resource_get_version (target)), 0); + wl_resource_set_implementation (offer->resource, &data_offer_interface, + offer, destroy_data_offer); + wl_resource_add_destroy_listener (source->resource, + &offer->source_destroy_listener); + + wl_data_device_send_data_offer (target, offer->resource); + + wl_array_for_each (p, &source->mime_types) + wl_data_offer_send_offer (offer->resource, *p); + + return offer->resource; +} + +static void +data_source_offer (struct wl_client *client, + struct wl_resource *resource, const char *type) +{ + MetaWaylandDataSource *source = wl_resource_get_user_data (resource); + char **p; + + p = wl_array_add (&source->mime_types, sizeof *p); + if (p) + *p = strdup (type); + if (!p || !*p) + wl_resource_post_no_memory (resource); +} + +static void +data_source_destroy (struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static struct wl_data_source_interface data_source_interface = { + data_source_offer, + data_source_destroy +}; + +typedef struct { + MetaWaylandPointerGrab generic; + + MetaWaylandSeat *seat; + struct wl_client *drag_client; + + MetaWaylandSurface *drag_focus; + struct wl_resource *drag_focus_data_device; + struct wl_listener drag_focus_listener; + + MetaWaylandSurface *drag_surface; + struct wl_listener drag_icon_listener; + + MetaWaylandDataSource *drag_data_source; + struct wl_listener drag_data_source_listener; +} MetaWaylandDragGrab; + +static void +destroy_drag_focus (struct wl_listener *listener, void *data) +{ + MetaWaylandDragGrab *grab = wl_container_of (listener, grab, drag_focus_listener); + + grab->drag_focus_data_device = NULL; +} + +static void +drag_grab_focus (MetaWaylandPointerGrab *grab, + MetaWaylandSurface *surface) +{ + MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab; + MetaWaylandSeat *seat = drag_grab->seat; + struct wl_resource *resource, *offer = NULL; + struct wl_display *display; + guint32 serial; + wl_fixed_t sx, sy; + + if (drag_grab->drag_focus == surface) + return; + + if (drag_grab->drag_focus_data_device) + { + wl_data_device_send_leave (drag_grab->drag_focus_data_device); + wl_list_remove (&drag_grab->drag_focus_listener.link); + drag_grab->drag_focus_data_device = NULL; + drag_grab->drag_focus = NULL; + } + + if (!surface) + return; + + if (!drag_grab->drag_data_source && + wl_resource_get_client (surface->resource) != drag_grab->drag_client) + return; + + resource = + wl_resource_find_for_client (&seat->data_device_resource_list, + wl_resource_get_client (surface->resource)); + if (!resource) + return; + + display = wl_client_get_display (wl_resource_get_client (resource)); + serial = wl_display_next_serial (display); + + if (drag_grab->drag_data_source) + offer = meta_wayland_data_source_send_offer (drag_grab->drag_data_source, + resource); + + meta_wayland_pointer_get_relative_coordinates (grab->pointer, surface, &sx, &sy); + wl_data_device_send_enter (resource, serial, surface->resource, + sx, sy, offer); + + drag_grab->drag_focus = surface; + + drag_grab->drag_focus_data_device = resource; + drag_grab->drag_focus_listener.notify = destroy_drag_focus; + wl_resource_add_destroy_listener (resource, &drag_grab->drag_focus_listener); +} + +static void +drag_grab_motion (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab; + wl_fixed_t sx, sy; + + if (drag_grab->drag_focus_data_device) + { + meta_wayland_pointer_get_relative_coordinates (grab->pointer, + drag_grab->drag_focus, + &sx, &sy); + wl_data_device_send_motion (drag_grab->drag_focus_data_device, + clutter_event_get_time (event), + sx, sy); + } +} + +static void +data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab) +{ + if (drag_grab->drag_surface) + { + drag_grab->drag_surface = NULL; + wl_list_remove (&drag_grab->drag_icon_listener.link); + } + + if (drag_grab->drag_data_source) + wl_list_remove (&drag_grab->drag_data_source_listener.link); + + drag_grab_focus (&drag_grab->generic, NULL); + + meta_wayland_pointer_end_grab (drag_grab->generic.pointer); + g_slice_free (MetaWaylandDragGrab, drag_grab); +} + +static void +drag_grab_button (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab; + MetaWaylandSeat *seat = drag_grab->seat; + ClutterEventType event_type = clutter_event_type (event); + + if (drag_grab->drag_focus_data_device && + drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) && + event_type == CLUTTER_BUTTON_RELEASE) + wl_data_device_send_drop (drag_grab->drag_focus_data_device); + + if (seat->pointer.button_count == 0 && + event_type == CLUTTER_BUTTON_RELEASE) + data_device_end_drag_grab (drag_grab); +} + +static const MetaWaylandPointerGrabInterface drag_grab_interface = { + drag_grab_focus, + drag_grab_motion, + drag_grab_button, +}; + +static void +destroy_data_device_source (struct wl_listener *listener, void *data) +{ + MetaWaylandDragGrab *drag_grab = + wl_container_of (listener, drag_grab, drag_data_source_listener); + + drag_grab->drag_data_source = NULL; + data_device_end_drag_grab (drag_grab); +} + +static void +destroy_data_device_icon (struct wl_listener *listener, void *data) +{ + MetaWaylandDragGrab *drag_grab = + wl_container_of (listener, drag_grab, drag_data_source_listener); + + drag_grab->drag_surface = NULL; +} + +static void +data_device_start_drag (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *source_resource, + struct wl_resource *origin_resource, + struct wl_resource *icon_resource, guint32 serial) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (resource); + MetaWaylandDragGrab *drag_grab; + + if ((seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + !seat->pointer.focus_surface || + seat->pointer.focus_surface != wl_resource_get_user_data (origin_resource))) + return; + + /* FIXME: Check that the data source type array isn't empty. */ + + if (seat->pointer.grab != &seat->pointer.default_grab) + return; + + drag_grab = g_slice_new0 (MetaWaylandDragGrab); + + drag_grab->generic.interface = &drag_grab_interface; + drag_grab->generic.pointer = &seat->pointer; + + drag_grab->drag_client = client; + drag_grab->seat = seat; + + if (source_resource) + { + drag_grab->drag_data_source = wl_resource_get_user_data (source_resource); + drag_grab->drag_data_source_listener.notify = destroy_data_device_source; + wl_resource_add_destroy_listener (source_resource, + &drag_grab->drag_data_source_listener); + } + + if (icon_resource) + { + drag_grab->drag_surface = wl_resource_get_user_data (icon_resource); + drag_grab->drag_icon_listener.notify = destroy_data_device_icon; + wl_resource_add_destroy_listener (icon_resource, + &drag_grab->drag_icon_listener); + } + + meta_wayland_pointer_set_focus (&seat->pointer, NULL); + meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*)drag_grab); +} + +static void +destroy_selection_data_source (struct wl_listener *listener, void *data) +{ + MetaWaylandSeat *seat = + wl_container_of (listener, seat, selection_data_source_listener); + struct wl_resource *data_device; + struct wl_resource *focus = NULL; + + seat->selection_data_source = NULL; + + focus = seat->keyboard.focus_resource; + + if (focus) + { + data_device = + wl_resource_find_for_client (&seat->data_device_resource_list, + wl_resource_get_client (focus)); + if (data_device) + wl_data_device_send_selection (data_device, NULL); + } +} + +static void +meta_wayland_seat_set_selection (MetaWaylandSeat *seat, + MetaWaylandDataSource *source, + guint32 serial) +{ + struct wl_resource *data_device, *offer; + struct wl_resource *focus = NULL; + + if (seat->selection_data_source && + seat->selection_serial - serial < UINT32_MAX / 2) + return; + + if (seat->selection_data_source) + { + wl_data_source_send_cancelled (seat->selection_data_source->resource); + wl_list_remove (&seat->selection_data_source_listener.link); + seat->selection_data_source = NULL; + } + + seat->selection_data_source = source; + seat->selection_serial = serial; + + focus = seat->keyboard.focus_resource; + + if (focus) + { + data_device = + wl_resource_find_for_client (&seat->data_device_resource_list, + wl_resource_get_client (focus)); + if (data_device && source) + { + offer = + meta_wayland_data_source_send_offer (seat->selection_data_source, + data_device); + wl_data_device_send_selection (data_device, offer); + } + else if (data_device) + { + wl_data_device_send_selection (data_device, NULL); + } + } + + if (source) + { + seat->selection_data_source_listener.notify = + destroy_selection_data_source; + wl_resource_add_destroy_listener (source->resource, + &seat->selection_data_source_listener); + } +} + +static void +data_device_set_selection (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *source_resource, + guint32 serial) +{ + if (!source_resource) + return; + + /* FIXME: Store serial and check against incoming serial here. */ + meta_wayland_seat_set_selection (wl_resource_get_user_data (resource), + wl_resource_get_user_data (source_resource), + serial); +} + +static const struct wl_data_device_interface data_device_interface = { + data_device_start_drag, + data_device_set_selection, +}; + +static void +destroy_data_source (struct wl_resource *resource) +{ + MetaWaylandDataSource *source = wl_resource_get_user_data (resource); + char **p; + + wl_array_for_each (p, &source->mime_types) free (*p); + + wl_array_release (&source->mime_types); + + g_slice_free (MetaWaylandDataSource, source); +} + +static void +create_data_source (struct wl_client *client, + struct wl_resource *resource, guint32 id) +{ + MetaWaylandDataSource *source = g_slice_new0 (MetaWaylandDataSource); + + source->resource = wl_resource_create (client, &wl_data_source_interface, + MIN (META_WL_DATA_SOURCE_VERSION, + wl_resource_get_version (resource)), id); + wl_resource_set_implementation (source->resource, &data_source_interface, + source, destroy_data_source); + + wl_array_init (&source->mime_types); +} + +static void +unbind_data_device (struct wl_resource *resource) +{ + wl_list_remove (wl_resource_get_link (resource)); +} + +static void +get_data_device (struct wl_client *client, + struct wl_resource *manager_resource, + guint32 id, struct wl_resource *seat_resource) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_data_device_interface, + MIN (META_WL_DATA_DEVICE_VERSION, + wl_resource_get_version (manager_resource)), id); + wl_resource_set_implementation (resource, &data_device_interface, seat, unbind_data_device); + wl_list_insert (&seat->data_device_resource_list, wl_resource_get_link (resource)); +} + +static const struct wl_data_device_manager_interface manager_interface = { + create_data_source, + get_data_device +}; + +static void +bind_manager (struct wl_client *client, + void *data, guint32 version, guint32 id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_data_device_manager_interface, + MIN (version, META_WL_DATA_DEVICE_MANAGER_VERSION), id); + wl_resource_set_implementation (resource, &manager_interface, NULL, NULL); +} + +void +meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat) +{ + struct wl_resource *data_device, *focus, *offer; + MetaWaylandDataSource *source; + + focus = seat->keyboard.focus_resource; + if (!focus) + return; + + data_device = wl_resource_find_for_client (&seat->data_device_resource_list, + wl_resource_get_client (focus)); + if (!data_device) + return; + + source = seat->selection_data_source; + if (source) + { + offer = meta_wayland_data_source_send_offer (source, data_device); + wl_data_device_send_selection (data_device, offer); + } +} + +int +meta_wayland_data_device_manager_init (struct wl_display *display) +{ + if (wl_global_create (display, + &wl_data_device_manager_interface, + META_WL_DATA_DEVICE_MANAGER_VERSION, + NULL, bind_manager) == NULL) + return -1; + + return 0; +} diff --git a/src/wayland/meta-wayland-data-device.h b/src/wayland/meta-wayland-data-device.h new file mode 100644 index 0000000..87f9774 --- /dev/null +++ b/src/wayland/meta-wayland-data-device.h @@ -0,0 +1,36 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __META_WAYLAND_DATA_DEVICE_H__ +#define __META_WAYLAND_DATA_DEVICE_H__ + +#include <wayland-server.h> + +#include "meta-wayland-seat.h" + +void +meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat); + +int +meta_wayland_data_device_manager_init (struct wl_display *display); + +#endif /* __META_WAYLAND_DATA_DEVICE_H__ */ diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c new file mode 100644 index 0000000..5aac8fb --- /dev/null +++ b/src/wayland/meta-wayland-keyboard.c @@ -0,0 +1,534 @@ +/* + * Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* + * Copyright © 2010-2011 Intel Corporation + * Copyright © 2008-2011 Kristian Høgsberg + * Copyright © 2012 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* The file is based on src/input.c from Weston */ + +#define _GNU_SOURCE + +#include "config.h" + +#include <glib.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <clutter/evdev/clutter-evdev.h> + +#include "meta-wayland-private.h" + +static int +create_anonymous_file (off_t size, + GError **error) +{ + static const char template[] = "mutter-shared-XXXXXX"; + char *path; + int fd, flags; + + fd = g_file_open_tmp (template, &path, error); + + if (fd == -1) + return -1; + + unlink (path); + g_free (path); + + flags = fcntl (fd, F_GETFD); + if (flags == -1) + goto err; + + if (fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1) + goto err; + + if (ftruncate (fd, size) < 0) + goto err; + + return fd; + + err: + g_set_error_literal (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + strerror (errno)); + close (fd); + + return -1; +} + +static void +inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard, + int flags) +{ + MetaWaylandCompositor *compositor; + struct wl_client *xclient; + struct wl_resource *keyboard_resource; + + compositor = meta_wayland_compositor_get_default (); + xclient = compositor->xwayland_manager.client; + + wl_resource_for_each (keyboard_resource, &keyboard->resource_list) + { + if ((flags & META_WAYLAND_KEYBOARD_SKIP_XCLIENTS) && + wl_resource_get_client (keyboard_resource) == xclient) + continue; + + wl_keyboard_send_keymap (keyboard_resource, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + keyboard->xkb_info.keymap_fd, + keyboard->xkb_info.keymap_size); + } +} + +static void +meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard, + struct xkb_keymap *keymap, + int flags) +{ + MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info; + GError *error = NULL; + char *keymap_str; + size_t previous_size; + + if (keymap == NULL) + { + g_warning ("Attempting to set null keymap (compilation probably failed)"); + return; + } + + xkb_keymap_unref (xkb_info->keymap); + xkb_info->keymap = keymap; + + xkb_state_unref (xkb_info->state); + xkb_info->state = xkb_state_new (keymap); + + keymap_str = xkb_map_get_as_string (xkb_info->keymap); + if (keymap_str == NULL) + { + g_warning ("failed to get string version of keymap"); + return; + } + previous_size = xkb_info->keymap_size; + xkb_info->keymap_size = strlen (keymap_str) + 1; + + if (xkb_info->keymap_fd >= 0) + close (xkb_info->keymap_fd); + + xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error); + if (xkb_info->keymap_fd < 0) + { + g_warning ("creating a keymap file for %lu bytes failed: %s", + (unsigned long) xkb_info->keymap_size, + error->message); + g_clear_error (&error); + goto err_keymap_str; + } + + if (xkb_info->keymap_area) + munmap (xkb_info->keymap_area, previous_size); + + xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, xkb_info->keymap_fd, 0); + if (xkb_info->keymap_area == MAP_FAILED) + { + g_warning ("failed to mmap() %lu bytes\n", + (unsigned long) xkb_info->keymap_size); + goto err_dev_zero; + } + strcpy (xkb_info->keymap_area, keymap_str); + free (keymap_str); + +#if defined(CLUTTER_WINDOWING_EGL) + /* XXX -- the evdev backend can be used regardless of the + * windowing backend. To do this properly we need a Clutter + * API to check the input backend. */ + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + { + ClutterDeviceManager *manager; + manager = clutter_device_manager_get_default (); + clutter_evdev_set_keyboard_map (manager, xkb_info->keymap); + } +#endif + + inform_clients_of_new_keymap (keyboard, flags); + + return; + +err_dev_zero: + close (xkb_info->keymap_fd); + xkb_info->keymap_fd = -1; +err_keymap_str: + free (keymap_str); + return; +} + +static void +keyboard_handle_focus_surface_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandKeyboard *keyboard = wl_container_of (listener, keyboard, focus_surface_listener); + + keyboard->focus_surface = NULL; + + if (keyboard->focus_resource) + { + wl_list_remove (&keyboard->focus_resource_listener.link); + keyboard->focus_resource = NULL; + } +} + +static void +keyboard_handle_focus_resource_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandKeyboard *keyboard = wl_container_of (listener, keyboard, focus_resource_listener); + + keyboard->focus_resource = NULL; +} + +static gboolean +default_grab_key (MetaWaylandKeyboardGrab *grab, + uint32_t time, uint32_t key, uint32_t state) +{ + MetaWaylandKeyboard *keyboard = grab->keyboard; + struct wl_resource *resource; + uint32_t serial; + + resource = keyboard->focus_resource; + if (resource) + { + struct wl_client *client = wl_resource_get_client (resource); + struct wl_display *display = wl_client_get_display (client); + serial = wl_display_next_serial (display); + wl_keyboard_send_key (resource, serial, time, key, state); + } + + return resource != NULL; +} + +static struct wl_resource * +find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface) +{ + struct wl_client *client; + + if (!surface) + return NULL; + + if (!surface->resource) + return NULL; + + client = wl_resource_get_client (surface->resource); + + return wl_resource_find_for_client (list, client); +} + +static void +default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial, + uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) +{ + MetaWaylandKeyboard *keyboard = grab->keyboard; + + if (keyboard->focus_resource) + { + wl_keyboard_send_modifiers (keyboard->focus_resource, serial, mods_depressed, + mods_latched, mods_locked, group); + } +} + +static const MetaWaylandKeyboardGrabInterface + default_keyboard_grab_interface = { + default_grab_key, + default_grab_modifiers, +}; + +gboolean +meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, + struct wl_display *display) +{ + memset (keyboard, 0, sizeof *keyboard); + keyboard->xkb_info.keymap_fd = -1; + + wl_list_init (&keyboard->resource_list); + wl_array_init (&keyboard->keys); + + keyboard->focus_surface_listener.notify = keyboard_handle_focus_surface_destroy; + keyboard->focus_resource_listener.notify = keyboard_handle_focus_resource_destroy; + + keyboard->default_grab.interface = &default_keyboard_grab_interface; + keyboard->default_grab.keyboard = keyboard; + keyboard->grab = &keyboard->default_grab; + + keyboard->display = display; + + keyboard->xkb_context = xkb_context_new (0 /* flags */); + + /* Compute a default until gnome-settings-daemon starts and sets + the appropriate values + */ + meta_wayland_keyboard_set_keymap_names (keyboard, + "evdev", + "pc105", + "us", "", "", 0); + + return TRUE; +} + +static void +meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info) +{ + xkb_keymap_unref (xkb_info->keymap); + xkb_state_unref (xkb_info->state); + + if (xkb_info->keymap_area) + munmap (xkb_info->keymap_area, xkb_info->keymap_size); + if (xkb_info->keymap_fd >= 0) + close (xkb_info->keymap_fd); +} + +static void +update_pressed_keys (MetaWaylandKeyboard *keyboard, + uint32_t evdev_code, + gboolean is_press) +{ + if (is_press) + { + uint32_t *end = (void *) ((char *) keyboard->keys.data + + keyboard->keys.size); + uint32_t *k; + + /* Make sure we don't already have this key. */ + for (k = keyboard->keys.data; k < end; k++) + if (*k == evdev_code) + return; + + /* Otherwise add the key to the list of pressed keys */ + k = wl_array_add (&keyboard->keys, sizeof (*k)); + *k = evdev_code; + } + else + { + uint32_t *end = (void *) ((char *) keyboard->keys.data + + keyboard->keys.size); + uint32_t *k; + + /* Remove the key from the array */ + for (k = keyboard->keys.data; k < end; k++) + if (*k == evdev_code) + { + *k = *(end - 1); + keyboard->keys.size -= sizeof (*k); + return; + } + + g_warning ("unexpected key release event for key 0x%x", evdev_code); + } +} + +static guint +evdev_code (const ClutterKeyEvent *event) +{ + /* clutter-xkb-utils.c adds a fixed offset of 8 to go into XKB's + * range, so we do the reverse here. */ + return event->hardware_keycode - 8; +} + +void +meta_wayland_keyboard_update (MetaWaylandKeyboard *keyboard, + const ClutterKeyEvent *event) +{ + MetaWaylandKeyboardGrab *grab = keyboard->grab; + gboolean is_press = event->type == CLUTTER_KEY_PRESS; + struct xkb_state *state = keyboard->xkb_info.state; + enum xkb_state_component changed_state; + + update_pressed_keys (keyboard, evdev_code (event), is_press); + + changed_state = xkb_state_update_key (state, + event->hardware_keycode, + is_press ? XKB_KEY_DOWN : XKB_KEY_UP); + if (changed_state == 0) + return; + + grab->interface->modifiers (grab, + wl_display_next_serial (keyboard->display), + xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED), + xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED), + xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED), + xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE)); +} + +gboolean +meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, + const ClutterKeyEvent *event) +{ + gboolean is_press = event->type == CLUTTER_KEY_PRESS; + gboolean handled; + + /* Synthetic key events are for autorepeat. Ignore those, as + * autorepeat in Wayland is done on the client side. */ + if (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC) + return FALSE; + + meta_verbose ("Handling key %s event code %d\n", + is_press ? "press" : "release", + event->hardware_keycode); + + handled = keyboard->grab->interface->key (keyboard->grab, + event->time, + evdev_code (event), + is_press); + + if (handled) + meta_verbose ("Sent event to wayland client\n"); + else + meta_verbose ("No wayland surface is focused, continuing normal operation\n"); + + return handled; +} + +void +meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard, + MetaWaylandSurface *surface) +{ + if (keyboard->focus_surface == surface && keyboard->focus_resource != NULL) + return; + + if (keyboard->focus_surface != NULL) + { + if (keyboard->focus_resource) + { + if (keyboard->focus_surface->resource) + { + struct wl_client *client = wl_resource_get_client (keyboard->focus_resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t serial = wl_display_next_serial (display); + wl_keyboard_send_leave (keyboard->focus_resource, serial, keyboard->focus_surface->resource); + } + + wl_list_remove (&keyboard->focus_resource_listener.link); + keyboard->focus_resource = NULL; + } + + wl_list_remove (&keyboard->focus_surface_listener.link); + keyboard->focus_surface = NULL; + } + + if (surface != NULL) + { + keyboard->focus_surface = surface; + wl_resource_add_destroy_listener (keyboard->focus_surface->resource, &keyboard->focus_surface_listener); + + keyboard->focus_resource = find_resource_for_surface (&keyboard->resource_list, surface); + if (keyboard->focus_resource) + { + struct wl_client *client = wl_resource_get_client (keyboard->focus_resource); + struct wl_display *display = wl_client_get_display (client); + struct xkb_state *state = keyboard->xkb_info.state; + uint32_t serial = wl_display_next_serial (display); + + wl_keyboard_send_modifiers (keyboard->focus_resource, serial, + xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED), + xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED), + xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED), + xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE)); + wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource, + &keyboard->keys); + + wl_resource_add_destroy_listener (keyboard->focus_resource, &keyboard->focus_resource_listener); + keyboard->focus_serial = serial; + } + } +} + +void +meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *keyboard, + MetaWaylandKeyboardGrab *grab) +{ + keyboard->grab = grab; + grab->keyboard = keyboard; + + /* XXX focus? */ +} + +void +meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard) +{ + keyboard->grab = &keyboard->default_grab; +} + +void +meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard) +{ + meta_wayland_xkb_info_destroy (&keyboard->xkb_info); + xkb_context_unref (keyboard->xkb_context); + + /* XXX: What about keyboard->resource_list? */ + wl_array_release (&keyboard->keys); +} + +void +meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard, + const char *rules, + const char *model, + const char *layout, + const char *variant, + const char *options, + int flags) +{ + struct xkb_rule_names xkb_names; + + xkb_names.rules = rules; + xkb_names.model = model; + xkb_names.layout = layout; + xkb_names.variant = variant; + xkb_names.options = options; + + meta_wayland_keyboard_take_keymap (keyboard, + xkb_keymap_new_from_names (keyboard->xkb_context, + &xkb_names, + 0 /* flags */), + flags); +} + diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h new file mode 100644 index 0000000..13fbf0a --- /dev/null +++ b/src/wayland/meta-wayland-keyboard.h @@ -0,0 +1,143 @@ +/* + * Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* + * Copyright © 2008-2011 Kristian Høgsberg + * Copyright © 2012 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __META_WAYLAND_KEYBOARD_H__ +#define __META_WAYLAND_KEYBOARD_H__ + +#include <clutter/clutter.h> +#include <wayland-server.h> +#include <xkbcommon/xkbcommon.h> + +struct _MetaWaylandKeyboardGrabInterface +{ + gboolean (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time, + uint32_t key, uint32_t state); + void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial, + uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group); +}; + +struct _MetaWaylandKeyboardGrab +{ + const MetaWaylandKeyboardGrabInterface *interface; + MetaWaylandKeyboard *keyboard; + MetaWaylandSurface *focus; + uint32_t key; +}; + +typedef struct +{ + struct xkb_keymap *keymap; + struct xkb_state *state; + int keymap_fd; + size_t keymap_size; + char *keymap_area; +} MetaWaylandXkbInfo; + +struct _MetaWaylandKeyboard +{ + struct wl_list resource_list; + + MetaWaylandSurface *focus_surface; + struct wl_listener focus_surface_listener; + struct wl_resource *focus_resource; + struct wl_listener focus_resource_listener; + uint32_t focus_serial; + + MetaWaylandKeyboardGrab *grab; + MetaWaylandKeyboardGrab default_grab; + uint32_t grab_key; + uint32_t grab_serial; + uint32_t grab_time; + + struct wl_array keys; + + struct wl_display *display; + + struct xkb_context *xkb_context; + MetaWaylandXkbInfo xkb_info; + + MetaWaylandKeyboardGrab input_method_grab; + struct wl_resource *input_method_resource; +}; + +gboolean +meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, + struct wl_display *display); + +typedef enum { + META_WAYLAND_KEYBOARD_SKIP_XCLIENTS = 1, +} MetaWaylandKeyboardSetKeymapFlags; + +void +meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard, + const char *rules, + const char *model, + const char *layout, + const char *variant, + const char *options, + int flags); +gboolean +meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, + const ClutterKeyEvent *event); + +void +meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard, + MetaWaylandSurface *surface); + +void +meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device, + MetaWaylandKeyboardGrab *grab); + +void +meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard); + +void +meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard); + +void +meta_wayland_keyboard_update (MetaWaylandKeyboard *keyboard, + const ClutterKeyEvent *event); + +#endif /* __META_WAYLAND_KEYBOARD_H__ */ diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c new file mode 100644 index 0000000..9e423a4 --- /dev/null +++ b/src/wayland/meta-wayland-pointer.c @@ -0,0 +1,598 @@ +/* + * Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Copyright © 2008 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* The file is based on src/input.c from Weston */ + +#include "config.h" + +#include <clutter/clutter.h> +#include <clutter/evdev/clutter-evdev.h> +#include <linux/input.h> + +#include "meta-wayland-pointer.h" +#include "meta-wayland-private.h" + +#include <string.h> + +static void meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer); + +static void +pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_surface_listener); + + pointer->focus_surface = NULL; + + if (pointer->focus_resource) + { + wl_list_remove (&pointer->focus_resource_listener.link); + pointer->focus_resource = NULL; + } +} + +static void +pointer_handle_focus_resource_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_resource_listener); + + pointer->focus_resource = NULL; +} + +static void +default_grab_focus (MetaWaylandPointerGrab *grab, + MetaWaylandSurface *surface) +{ + MetaWaylandPointer *pointer = grab->pointer; + + if (pointer->button_count > 0) + return; + + meta_wayland_pointer_set_focus (pointer, surface); +} + +static void +default_grab_motion (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + struct wl_resource *resource; + + resource = grab->pointer->focus_resource; + if (resource) + { + wl_fixed_t sx, sy; + + meta_wayland_pointer_get_relative_coordinates (grab->pointer, + grab->pointer->focus_surface, + &sx, &sy); + wl_pointer_send_motion (resource, clutter_event_get_time (event), sx, sy); + } +} + +static void +default_grab_button (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + MetaWaylandPointer *pointer = grab->pointer; + struct wl_resource *resource; + ClutterEventType event_type; + + event_type = clutter_event_type (event); + + resource = pointer->focus_resource; + if (resource) + { + struct wl_client *client = wl_resource_get_client (resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t button; + uint32_t serial; + + button = clutter_event_get_button (event); + switch (button) + { + /* The evdev input right and middle button numbers are swapped + relative to how Clutter numbers them */ + case 2: + button = BTN_MIDDLE; + break; + + case 3: + button = BTN_RIGHT; + break; + + default: + button = button + BTN_LEFT - 1; + break; + } + + serial = wl_display_next_serial (display); + wl_pointer_send_button (resource, serial, + clutter_event_get_time (event), button, + event_type == CLUTTER_BUTTON_PRESS ? 1 : 0); + } + + if (pointer->button_count == 0 && event_type == CLUTTER_BUTTON_RELEASE) + meta_wayland_pointer_set_focus (pointer, pointer->current); +} + +static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = { + default_grab_focus, + default_grab_motion, + default_grab_button +}; + +/* + * The pointer constrain code is mostly a rip-off of the XRandR code from Xorg. + * (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder) + * + * Copyright © 2006 Keith Packard + * Copyright 2010 Red Hat, Inc + * + */ + +static gboolean +check_all_screen_monitors(MetaMonitorInfo *monitors, + unsigned n_monitors, + float x, + float y) +{ + unsigned int i; + + for (i = 0; i < n_monitors; i++) + { + MetaMonitorInfo *monitor = &monitors[i]; + int left, right, top, bottom; + + left = monitor->rect.x; + right = left + monitor->rect.width; + top = monitor->rect.y; + bottom = left + monitor->rect.height; + + if ((x >= left) && (x < right) && (y >= top) && (y < bottom)) + return TRUE; + } + + return FALSE; +} + +static void +constrain_all_screen_monitors (ClutterInputDevice *device, + MetaMonitorInfo *monitors, + unsigned n_monitors, + float *x, + float *y) +{ + ClutterPoint current; + unsigned int i; + + clutter_input_device_get_coords (device, NULL, ¤t); + + /* if we're trying to escape, clamp to the CRTC we're coming from */ + for (i = 0; i < n_monitors; i++) + { + MetaMonitorInfo *monitor = &monitors[i]; + int left, right, top, bottom; + float nx, ny; + + left = monitor->rect.x; + right = left + monitor->rect.width; + top = monitor->rect.y; + bottom = left + monitor->rect.height; + + nx = current.x; + ny = current.y; + + if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) + { + if (*x < left) + *x = left; + if (*x >= right) + *x = right - 1; + if (*y < top) + *y = top; + if (*y >= bottom) + *y = bottom - 1; + + return; + } + } +} + +static void +pointer_constrain_callback (ClutterInputDevice *device, + guint32 time, + float *new_x, + float *new_y, + gpointer user_data) +{ + MetaMonitorManager *monitor_manager; + MetaMonitorInfo *monitors; + unsigned int n_monitors; + gboolean ret; + + monitor_manager = meta_monitor_manager_get (); + monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors); + + /* if we're moving inside a monitor, we're fine */ + ret = check_all_screen_monitors(monitors, n_monitors, *new_x, *new_y); + if (ret == TRUE) + return; + + /* if we're trying to escape, clamp to the CRTC we're coming from */ + constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y); +} + +void +meta_wayland_pointer_init (MetaWaylandPointer *pointer) +{ + ClutterDeviceManager *manager; + ClutterInputDevice *device; + ClutterPoint current; + + memset (pointer, 0, sizeof *pointer); + wl_list_init (&pointer->resource_list); + + pointer->focus_surface_listener.notify = pointer_handle_focus_surface_destroy; + pointer->focus_resource_listener.notify = pointer_handle_focus_resource_destroy; + + pointer->default_grab.interface = &default_pointer_grab_interface; + pointer->default_grab.pointer = pointer; + pointer->grab = &pointer->default_grab; + + manager = clutter_device_manager_get_default (); + device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE); + +#if defined(CLUTTER_WINDOWING_EGL) + /* XXX -- the evdev backend can be used regardless of the + * windowing backend. To do this properly we need a Clutter + * API to check the input backend. */ + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + { + clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback, + pointer, NULL); + } +#endif + + clutter_input_device_get_coords (device, NULL, ¤t); + pointer->x = wl_fixed_from_double (current.x); + pointer->y = wl_fixed_from_double (current.y); +} + +void +meta_wayland_pointer_release (MetaWaylandPointer *pointer) +{ + /* Do nothing. */ +} + +static struct wl_resource * +find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface) +{ + struct wl_client *client; + + if (!surface) + return NULL; + + g_assert (surface->resource); + client = wl_resource_get_client (surface->resource); + + return wl_resource_find_for_client (list, client); +} + +void +meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface) +{ + if (pointer->focus_surface == surface && pointer->focus_resource != NULL) + return; + + if (pointer->focus_surface) + { + if (pointer->focus_resource) + { + if (pointer->focus_surface->resource) + { + struct wl_client *client = wl_resource_get_client (pointer->focus_resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t serial = wl_display_next_serial (display); + wl_pointer_send_leave (pointer->focus_resource, serial, pointer->focus_surface->resource); + } + + wl_list_remove (&pointer->focus_resource_listener.link); + pointer->focus_resource = NULL; + } + + wl_list_remove (&pointer->focus_surface_listener.link); + pointer->focus_surface = NULL; + } + + if (surface != NULL) + { + pointer->focus_surface = surface; + wl_resource_add_destroy_listener (pointer->focus_surface->resource, &pointer->focus_surface_listener); + + pointer->focus_resource = find_resource_for_surface (&pointer->resource_list, surface); + if (pointer->focus_resource) + { + struct wl_client *client = wl_resource_get_client (pointer->focus_resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t serial = wl_display_next_serial (display); + + meta_window_handle_enter (pointer->focus_surface->window, + /* XXX -- can we reliably get a timestamp for setting focus? */ + clutter_get_current_event_time (), + wl_fixed_to_int (pointer->x), + wl_fixed_to_int (pointer->y)); + + { + wl_fixed_t sx, sy; + + meta_wayland_pointer_get_relative_coordinates (pointer, pointer->focus_surface, &sx, &sy); + wl_pointer_send_enter (pointer->focus_resource, serial, pointer->focus_surface->resource, sx, sy); + } + + wl_resource_add_destroy_listener (pointer->focus_resource, &pointer->focus_resource_listener); + pointer->focus_serial = serial; + } + } +} + +void +meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer, + MetaWaylandPointerGrab *grab) +{ + const MetaWaylandPointerGrabInterface *interface; + + pointer->grab = grab; + interface = pointer->grab->interface; + grab->pointer = pointer; + + if (pointer->current) + interface->focus (pointer->grab, pointer->current); +} + +void +meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer) +{ + const MetaWaylandPointerGrabInterface *interface; + + pointer->grab = &pointer->default_grab; + interface = pointer->grab->interface; + interface->focus (pointer->grab, pointer->current); +} + +typedef struct { + MetaWaylandPointerGrab generic; + + struct wl_client *grab_client; + struct wl_list all_popups; +} MetaWaylandPopupGrab; + +typedef struct { + MetaWaylandPopupGrab *grab; + MetaWaylandSurface *surface; + struct wl_listener surface_destroy_listener; + + struct wl_list link; +} MetaWaylandPopup; + +static void +popup_grab_focus (MetaWaylandPointerGrab *grab, + MetaWaylandSurface *surface) +{ + MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab; + + /* Popup grabs are in owner-events mode (ie, events for the same client + are reported as normal) */ + if (surface && wl_resource_get_client (surface->resource) == popup_grab->grab_client) + default_grab_focus (grab, surface); + else + meta_wayland_pointer_set_focus (grab->pointer, NULL); +} + +static void +popup_grab_motion (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + default_grab_motion (grab, event); +} + +static void +popup_grab_button (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab; + MetaWaylandPointer *pointer = grab->pointer; + + if (pointer->focus_resource) + { + /* This is ensured by popup_grab_focus */ + g_assert (wl_resource_get_client (pointer->focus_resource) == popup_grab->grab_client); + + default_grab_button (grab, event); + } + else if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE && + pointer->button_count == 0) + meta_wayland_pointer_end_popup_grab (grab->pointer); +} + +static MetaWaylandPointerGrabInterface popup_grab_interface = { + popup_grab_focus, + popup_grab_motion, + popup_grab_button +}; + +static void +meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer) +{ + MetaWaylandPopupGrab *popup_grab; + MetaWaylandPopup *popup, *tmp; + + popup_grab = (MetaWaylandPopupGrab*)pointer->grab; + + g_assert (popup_grab->generic.interface == &popup_grab_interface); + + wl_list_for_each_safe (popup, tmp, &popup_grab->all_popups, link) + { + meta_wayland_surface_popup_done (popup->surface); + wl_list_remove (&popup->surface_destroy_listener.link); + wl_list_remove (&popup->link); + g_slice_free (MetaWaylandPopup, popup); + } + + { + MetaDisplay *display = meta_get_display (); + meta_display_end_grab_op (display, + meta_display_get_current_time_roundtrip (display)); + } + + meta_wayland_pointer_end_grab (pointer); + g_slice_free (MetaWaylandPopupGrab, popup_grab); +} + +static void +on_popup_surface_destroy (struct wl_listener *listener, + void *data) +{ + MetaWaylandPopup *popup = + wl_container_of (listener, popup, surface_destroy_listener); + MetaWaylandPopupGrab *popup_grab = popup->grab; + + wl_list_remove (&popup->link); + g_slice_free (MetaWaylandPopup, popup); + + if (wl_list_empty (&popup_grab->all_popups)) + meta_wayland_pointer_end_popup_grab (popup_grab->generic.pointer); +} + +gboolean +meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface) +{ + MetaWaylandPopupGrab *grab; + MetaWaylandPopup *popup; + + if (pointer->grab != &pointer->default_grab) + { + if (pointer->grab->interface != &popup_grab_interface) + return FALSE; + + grab = (MetaWaylandPopupGrab*)pointer->grab; + + if (wl_resource_get_client (surface->resource) != grab->grab_client) + return FALSE; + } + + if (pointer->grab == &pointer->default_grab) + { + MetaWindow *window = surface->window; + + grab = g_slice_new0 (MetaWaylandPopupGrab); + grab->generic.interface = &popup_grab_interface; + grab->generic.pointer = pointer; + grab->grab_client = wl_resource_get_client (surface->resource); + wl_list_init (&grab->all_popups); + + meta_wayland_pointer_start_grab (pointer, (MetaWaylandPointerGrab*)grab); + + meta_display_begin_grab_op (window->display, + window->screen, + window, + META_GRAB_OP_WAYLAND_CLIENT, + FALSE, /* pointer_already_grabbed */ + FALSE, /* frame_action */ + 1, /* button. XXX? */ + 0, /* modmask */ + meta_display_get_current_time_roundtrip (window->display), + wl_fixed_to_int (pointer->grab_x), + wl_fixed_to_int (pointer->grab_y)); + + } + else + grab = (MetaWaylandPopupGrab*)pointer->grab; + + popup = g_slice_new0 (MetaWaylandPopup); + popup->grab = grab; + popup->surface = surface; + popup->surface_destroy_listener.notify = on_popup_surface_destroy; + if (surface->xdg_popup.resource) + wl_resource_add_destroy_listener (surface->xdg_popup.resource, &popup->surface_destroy_listener); + else if (surface->wl_shell_surface.resource) + wl_resource_add_destroy_listener (surface->wl_shell_surface.resource, &popup->surface_destroy_listener); + + wl_list_insert (&grab->all_popups, &popup->link); + return TRUE; +} + +void +meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface, + wl_fixed_t *sx, + wl_fixed_t *sy) +{ + float xf = 0.0f, yf = 0.0f; + + if (surface->window) + { + ClutterActor *actor = + CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window)); + + if (actor) + clutter_actor_transform_stage_point (actor, + wl_fixed_to_double (pointer->x), + wl_fixed_to_double (pointer->y), + &xf, &yf); + } + + *sx = wl_fixed_from_double (xf); + *sy = wl_fixed_from_double (yf); +} + +void +meta_wayland_pointer_update_current_focus (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface) +{ + pointer->current = surface; + if (surface != pointer->focus_surface) + { + const MetaWaylandPointerGrabInterface *interface = + pointer->grab->interface; + interface->focus (pointer->grab, surface); + } +} diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h new file mode 100644 index 0000000..d5e3038 --- /dev/null +++ b/src/wayland/meta-wayland-pointer.h @@ -0,0 +1,101 @@ +/* + * Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __META_WAYLAND_POINTER_H__ +#define __META_WAYLAND_POINTER_H__ + +#include <wayland-server.h> + +#include <glib.h> + +#include "meta-wayland-types.h" + +struct _MetaWaylandPointerGrabInterface +{ + void (*focus) (MetaWaylandPointerGrab *grab, + MetaWaylandSurface *surface); + void (*motion) (MetaWaylandPointerGrab *grab, + const ClutterEvent *event); + void (*button) (MetaWaylandPointerGrab *grab, + const ClutterEvent *event); +}; + +struct _MetaWaylandPointerGrab +{ + const MetaWaylandPointerGrabInterface *interface; + MetaWaylandPointer *pointer; +}; + +struct _MetaWaylandPointer +{ + struct wl_list resource_list; + + MetaWaylandSurface *focus_surface; + struct wl_listener focus_surface_listener; + struct wl_resource *focus_resource; + struct wl_listener focus_resource_listener; + guint32 focus_serial; + guint32 click_serial; + + MetaWaylandPointerGrab *grab; + MetaWaylandPointerGrab default_grab; + wl_fixed_t grab_x, grab_y; + wl_fixed_t focus_x, focus_y; + guint32 grab_button; + guint32 grab_serial; + guint32 grab_time; + + wl_fixed_t x, y; /* TODO: remove, use ClutterInputDevice instead */ + MetaWaylandSurface *current; + + guint32 button_count; +}; + +void +meta_wayland_pointer_init (MetaWaylandPointer *pointer); + +void +meta_wayland_pointer_release (MetaWaylandPointer *pointer); + +void +meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface); + +void +meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer, + MetaWaylandPointerGrab *grab); + +void +meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer); + +gboolean +meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, + MetaWaylandSurface *popup); + +void +meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface, + wl_fixed_t *x, + wl_fixed_t *y); + +void +meta_wayland_pointer_update_current_focus (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface); + +#endif /* __META_WAYLAND_POINTER_H__ */ diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h new file mode 100644 index 0000000..d575e2f --- /dev/null +++ b/src/wayland/meta-wayland-private.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_WAYLAND_PRIVATE_H +#define META_WAYLAND_PRIVATE_H + +#include <wayland-server.h> +#include <clutter/clutter.h> + +#include <glib.h> +#include <cairo.h> + +#include "window-private.h" +#include <meta/meta-cursor-tracker.h> + +#include "meta-wayland.h" +#include "meta-wayland-versions.h" +#include "meta-wayland-surface.h" +#include "meta-wayland-seat.h" + +typedef struct +{ + struct wl_resource *resource; + cairo_region_t *region; +} MetaWaylandRegion; + +typedef struct +{ + GSource source; + GPollFD pfd; + struct wl_display *display; +} WaylandEventSource; + +typedef struct +{ + struct wl_list link; + + /* Pointer back to the compositor */ + MetaWaylandCompositor *compositor; + + struct wl_resource *resource; +} MetaWaylandFrameCallback; + +typedef struct +{ + int display_index; + char *lockfile; + int abstract_fd; + int unix_fd; + pid_t pid; + struct wl_client *client; + struct wl_resource *xserver_resource; + char *display_name; + + GMainLoop *init_loop; +} MetaXWaylandManager; + +struct _MetaWaylandCompositor +{ + struct wl_display *wayland_display; + char *display_name; + struct wl_event_loop *wayland_loop; + ClutterActor *stage; + GHashTable *outputs; + GSource *wayland_event_source; + GList *surfaces; + struct wl_list frame_callbacks; + + MetaXWaylandManager xwayland_manager; + + MetaWaylandSeat *seat; +}; + +MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource); +void meta_wayland_buffer_ref (MetaWaylandBuffer *buffer); +void meta_wayland_buffer_unref (MetaWaylandBuffer *buffer); + +#endif /* META_WAYLAND_PRIVATE_H */ diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c new file mode 100644 index 0000000..f5e3867 --- /dev/null +++ b/src/wayland/meta-wayland-seat.c @@ -0,0 +1,503 @@ +/* + * Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include <cogl/cogl-wayland-server.h> +#include <clutter/clutter.h> +#include <clutter/wayland/clutter-wayland-compositor.h> +#include <clutter/wayland/clutter-wayland-surface.h> +#include <linux/input.h> +#include <stdlib.h> +#include <string.h> +#include "meta-wayland-seat.h" +#include "meta-wayland-private.h" +#include "meta-wayland-keyboard.h" +#include "meta-wayland-pointer.h" +#include "meta-wayland-data-device.h" +#include "meta-window-actor-private.h" +#include "meta/meta-shaped-texture.h" +#include "meta-shaped-texture-private.h" +#include "meta-wayland-stage.h" +#include "meta-cursor-tracker-private.h" +#include "meta-surface-actor-wayland.h" + +#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10) + +static void +unbind_resource (struct wl_resource *resource) +{ + wl_list_remove (wl_resource_get_link (resource)); +} + +static void +set_cursor_surface (MetaWaylandSeat *seat, + MetaWaylandSurface *surface) +{ + if (seat->cursor_surface == surface) + return; + + if (seat->cursor_surface) + wl_list_remove (&seat->cursor_surface_destroy_listener.link); + + seat->cursor_surface = surface; + + if (seat->cursor_surface) + wl_resource_add_destroy_listener (seat->cursor_surface->resource, + &seat->cursor_surface_destroy_listener); +} + +void +meta_wayland_seat_update_cursor_surface (MetaWaylandSeat *seat) +{ + MetaCursorReference *cursor; + + if (seat->cursor_tracker == NULL) + return; + + if (seat->cursor_surface && seat->cursor_surface->buffer) + { + struct wl_resource *buffer = seat->cursor_surface->buffer->resource; + cursor = meta_cursor_reference_from_buffer (seat->cursor_tracker, + buffer, + seat->hotspot_x, + seat->hotspot_y); + } + else + cursor = NULL; + + meta_cursor_tracker_set_window_cursor (seat->cursor_tracker, cursor); + + if (cursor) + meta_cursor_reference_unref (cursor); +} + +static void +pointer_set_cursor (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + struct wl_resource *surface_resource, + int32_t x, int32_t y) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface; + + surface = (surface_resource ? wl_resource_get_user_data (surface_resource) : NULL); + + if (seat->pointer.focus_surface == NULL) + return; + if (wl_resource_get_client (seat->pointer.focus_surface->resource) != client) + return; + if (seat->pointer.focus_serial - serial > G_MAXUINT32 / 2) + return; + + seat->hotspot_x = x; + seat->hotspot_y = y; + set_cursor_surface (seat, surface); + meta_wayland_seat_update_cursor_surface (seat); +} + +static void +pointer_release (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct wl_pointer_interface pointer_interface = { + pointer_set_cursor, + pointer_release, +}; + +static void +seat_get_pointer (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (resource); + struct wl_resource *cr; + + cr = wl_resource_create (client, &wl_pointer_interface, + MIN (META_WL_POINTER_VERSION, wl_resource_get_version (resource)), id); + wl_resource_set_implementation (cr, &pointer_interface, seat, unbind_resource); + wl_list_insert (&seat->pointer.resource_list, wl_resource_get_link (cr)); + + if (seat->pointer.focus_surface && + wl_resource_get_client (seat->pointer.focus_surface->resource) == client) + meta_wayland_pointer_set_focus (&seat->pointer, seat->pointer.focus_surface); +} + +static void +keyboard_release (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct wl_keyboard_interface keyboard_interface = { + keyboard_release, +}; + +static void +seat_get_keyboard (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (resource); + struct wl_resource *cr; + + cr = wl_resource_create (client, &wl_keyboard_interface, + MIN (META_WL_KEYBOARD_VERSION, wl_resource_get_version (resource)), id); + wl_resource_set_implementation (cr, NULL, seat, unbind_resource); + wl_list_insert (&seat->keyboard.resource_list, wl_resource_get_link (cr)); + + wl_keyboard_send_keymap (cr, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + seat->keyboard.xkb_info.keymap_fd, + seat->keyboard.xkb_info.keymap_size); + + if (seat->keyboard.focus_surface && + wl_resource_get_client (seat->keyboard.focus_surface->resource) == client) + { + meta_wayland_keyboard_set_focus (&seat->keyboard, seat->keyboard.focus_surface); + meta_wayland_data_device_set_keyboard_focus (seat); + } +} + +static void +seat_get_touch (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + /* Touch not supported */ +} + +static const struct wl_seat_interface +seat_interface = + { + seat_get_pointer, + seat_get_keyboard, + seat_get_touch + }; + +static void +bind_seat (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + MetaWaylandSeat *seat = data; + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_seat_interface, + MIN (META_WL_SEAT_VERSION, version), id); + wl_resource_set_implementation (resource, &seat_interface, seat, unbind_resource); + wl_list_insert (&seat->base_resource_list, wl_resource_get_link (resource)); + + wl_seat_send_capabilities (resource, + WL_SEAT_CAPABILITY_POINTER | + WL_SEAT_CAPABILITY_KEYBOARD); + + if (version >= META_WL_SEAT_HAS_NAME) + wl_seat_send_name (resource, "seat0"); +} + +static void +pointer_handle_cursor_surface_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandSeat *seat = wl_container_of (listener, seat, cursor_surface_destroy_listener); + + set_cursor_surface (seat, NULL); + meta_wayland_seat_update_cursor_surface (seat); +} + +MetaWaylandSeat * +meta_wayland_seat_new (struct wl_display *display) +{ + MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1); + + seat->selection_data_source = NULL; + wl_list_init (&seat->base_resource_list); + wl_list_init (&seat->data_device_resource_list); + + meta_wayland_pointer_init (&seat->pointer); + meta_wayland_keyboard_init (&seat->keyboard, display); + + seat->display = display; + + seat->current_stage = 0; + + seat->cursor_surface = NULL; + seat->cursor_surface_destroy_listener.notify = pointer_handle_cursor_surface_destroy; + seat->hotspot_x = 16; + seat->hotspot_y = 16; + + wl_global_create (display, &wl_seat_interface, META_WL_SEAT_VERSION, seat, bind_seat); + + return seat; +} + +static void +notify_motion (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + MetaWaylandPointer *pointer = &seat->pointer; + + meta_wayland_seat_repick (seat, event); + + pointer->grab->interface->motion (pointer->grab, event); +} + +static void +handle_motion_event (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + notify_motion (seat, event); +} + +static void +handle_button_event (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + MetaWaylandPointer *pointer = &seat->pointer; + gboolean implicit_grab; + + notify_motion (seat, event); + + implicit_grab = (event->type == CLUTTER_BUTTON_PRESS) && (pointer->button_count == 1); + if (implicit_grab) + { + pointer->grab_button = clutter_event_get_button (event); + pointer->grab_time = clutter_event_get_time (event); + pointer->grab_x = pointer->x; + pointer->grab_y = pointer->y; + } + + pointer->grab->interface->button (pointer->grab, event); + + if (implicit_grab) + pointer->grab_serial = wl_display_get_serial (seat->display); +} + +static void +handle_scroll_event (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + wl_fixed_t x_value = 0, y_value = 0; + + notify_motion (seat, event); + + if (!seat->pointer.focus_resource) + return; + + if (clutter_event_is_pointer_emulated (event)) + return; + + switch (clutter_event_get_scroll_direction (event)) + { + case CLUTTER_SCROLL_UP: + y_value = -DEFAULT_AXIS_STEP_DISTANCE; + break; + + case CLUTTER_SCROLL_DOWN: + y_value = DEFAULT_AXIS_STEP_DISTANCE; + break; + + case CLUTTER_SCROLL_LEFT: + x_value = -DEFAULT_AXIS_STEP_DISTANCE; + break; + + case CLUTTER_SCROLL_RIGHT: + x_value = DEFAULT_AXIS_STEP_DISTANCE; + break; + + case CLUTTER_SCROLL_SMOOTH: + { + double dx, dy; + clutter_event_get_scroll_delta (event, &dx, &dy); + x_value = wl_fixed_from_double (dx); + y_value = wl_fixed_from_double (dy); + } + break; + + default: + return; + } + + if (x_value) + wl_pointer_send_axis (seat->pointer.focus_resource, clutter_event_get_time (event), + WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value); + if (y_value) + wl_pointer_send_axis (seat->pointer.focus_resource, clutter_event_get_time (event), + WL_POINTER_AXIS_VERTICAL_SCROLL, y_value); +} + +static int +count_buttons (const ClutterEvent *event) +{ + static gint maskmap[5] = + { + CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON2_MASK, CLUTTER_BUTTON3_MASK, + CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK + }; + ClutterModifierType mod_mask; + int i, count; + + mod_mask = clutter_event_get_state (event); + count = 0; + for (i = 0; i < 5; i++) + { + if (mod_mask & maskmap[i]) + count++; + } + + return count; +} + +static void +meta_wayland_seat_update_pointer (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + float x, y; + + clutter_event_get_coords (event, &x, &y); + seat->pointer.x = wl_fixed_from_double (x); + seat->pointer.y = wl_fixed_from_double (y); + + seat->pointer.button_count = count_buttons (event); + + if (seat->cursor_tracker) + { + meta_cursor_tracker_update_position (seat->cursor_tracker, + wl_fixed_to_int (seat->pointer.x), + wl_fixed_to_int (seat->pointer.y)); + + if (seat->pointer.current == NULL) + meta_cursor_tracker_unset_window_cursor (seat->cursor_tracker); + } +} + +void +meta_wayland_seat_update (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + switch (event->type) + { + case CLUTTER_MOTION: + case CLUTTER_BUTTON_PRESS: + case CLUTTER_BUTTON_RELEASE: + case CLUTTER_SCROLL: + meta_wayland_seat_update_pointer (seat, event); + break; + case CLUTTER_KEY_PRESS: + case CLUTTER_KEY_RELEASE: + meta_wayland_keyboard_update (&seat->keyboard, (const ClutterKeyEvent *) event); + break; + default: + break; + } +} + +gboolean +meta_wayland_seat_handle_event (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + switch (event->type) + { + case CLUTTER_MOTION: + handle_motion_event (seat, event); + break; + + case CLUTTER_BUTTON_PRESS: + case CLUTTER_BUTTON_RELEASE: + handle_button_event (seat, event); + break; + + case CLUTTER_KEY_PRESS: + case CLUTTER_KEY_RELEASE: + return meta_wayland_keyboard_handle_event (&seat->keyboard, + (const ClutterKeyEvent *) event); + + case CLUTTER_SCROLL: + handle_scroll_event (seat, event); + break; + + default: + break; + } + + return FALSE; +} + +/* The actor argument can be NULL in which case a Clutter pick will be + performed to determine the right actor. An actor should only be + passed if the repick is being performed due to an event in which + case Clutter will have already performed a pick so we can avoid + redundantly doing another one */ +void +meta_wayland_seat_repick (MetaWaylandSeat *seat, + const ClutterEvent *for_event) +{ + ClutterActor *actor = NULL; + MetaWaylandPointer *pointer = &seat->pointer; + MetaWaylandSurface *surface = NULL; + MetaDisplay *display = meta_get_display (); + + if (meta_grab_op_is_wayland (display->grab_op)) + { + meta_wayland_pointer_update_current_focus (pointer, NULL); + return; + } + + if (for_event) + { + actor = clutter_event_get_source (for_event); + } + else if (seat->current_stage) + { + ClutterStage *stage = CLUTTER_STAGE (seat->current_stage); + actor = clutter_stage_get_actor_at_pos (stage, + CLUTTER_PICK_REACTIVE, + wl_fixed_to_double (pointer->x), + wl_fixed_to_double (pointer->y)); + } + + if (actor) + seat->current_stage = clutter_actor_get_stage (actor); + else + seat->current_stage = NULL; + + if (META_IS_SURFACE_ACTOR_WAYLAND (actor)) + surface = meta_surface_actor_wayland_get_surface (META_SURFACE_ACTOR_WAYLAND (actor)); + + meta_wayland_pointer_update_current_focus (pointer, surface); +} + +void +meta_wayland_seat_free (MetaWaylandSeat *seat) +{ + set_cursor_surface (seat, NULL); + + meta_wayland_pointer_release (&seat->pointer); + meta_wayland_keyboard_release (&seat->keyboard); + + g_slice_free (MetaWaylandSeat, seat); +} diff --git a/src/wayland/meta-wayland-seat.h b/src/wayland/meta-wayland-seat.h new file mode 100644 index 0000000..a038e2e --- /dev/null +++ b/src/wayland/meta-wayland-seat.h @@ -0,0 +1,91 @@ +/* + * Wayland Support + * + * Copyright (C) 2012 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __META_WAYLAND_SEAT_H__ +#define __META_WAYLAND_SEAT_H__ + +#include <wayland-server.h> +#include <xkbcommon/xkbcommon.h> +#include <clutter/clutter.h> +#include <glib.h> + +#include <meta/meta-cursor-tracker.h> +#include "meta-wayland-types.h" +#include "meta-wayland-keyboard.h" +#include "meta-wayland-pointer.h" + +struct _MetaWaylandDataOffer +{ + struct wl_resource *resource; + MetaWaylandDataSource *source; + struct wl_listener source_destroy_listener; +}; + +struct _MetaWaylandDataSource +{ + struct wl_resource *resource; + struct wl_array mime_types; +}; + +struct _MetaWaylandSeat +{ + struct wl_list base_resource_list; + + uint32_t selection_serial; + MetaWaylandDataSource *selection_data_source; + struct wl_listener selection_data_source_listener; + + struct wl_list data_device_resource_list; + MetaWaylandPointer pointer; + MetaWaylandKeyboard keyboard; + + struct wl_display *display; + + MetaCursorTracker *cursor_tracker; + MetaWaylandSurface *cursor_surface; + int hotspot_x, hotspot_y; + struct wl_listener cursor_surface_destroy_listener; + + ClutterActor *current_stage; +}; + +MetaWaylandSeat * +meta_wayland_seat_new (struct wl_display *display); + +void +meta_wayland_seat_update (MetaWaylandSeat *seat, + const ClutterEvent *event); + +gboolean +meta_wayland_seat_handle_event (MetaWaylandSeat *seat, + const ClutterEvent *event); + +void +meta_wayland_seat_repick (MetaWaylandSeat *seat, + const ClutterEvent *for_event); + +void +meta_wayland_seat_update_cursor_surface (MetaWaylandSeat *seat); + +void +meta_wayland_seat_free (MetaWaylandSeat *seat); + +#endif /* __META_WAYLAND_SEAT_H__ */ diff --git a/src/wayland/meta-wayland-stage.c b/src/wayland/meta-wayland-stage.c new file mode 100644 index 0000000..b795dd5 --- /dev/null +++ b/src/wayland/meta-wayland-stage.c @@ -0,0 +1,68 @@ +/* + * Wayland Support + * + * Copyright (C) 2012 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <config.h> + +#include <clutter/clutter.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <cogl/cogl-wayland-server.h> + +#include "meta-wayland-stage.h" +#include "meta-wayland-private.h" +#include "meta/meta-window-actor.h" +#include "meta/meta-shaped-texture.h" +#include "meta-cursor-tracker-private.h" + +G_DEFINE_TYPE (MetaWaylandStage, meta_wayland_stage, CLUTTER_TYPE_STAGE); + +static void +meta_wayland_stage_paint (ClutterActor *actor) +{ + MetaWaylandCompositor *compositor; + + CLUTTER_ACTOR_CLASS (meta_wayland_stage_parent_class)->paint (actor); + + compositor = meta_wayland_compositor_get_default (); + if (compositor->seat->cursor_tracker) + meta_cursor_tracker_paint (compositor->seat->cursor_tracker); +} + +static void +meta_wayland_stage_class_init (MetaWaylandStageClass *klass) +{ + ClutterActorClass *actor_class = (ClutterActorClass *) klass; + + actor_class->paint = meta_wayland_stage_paint; +} + +static void +meta_wayland_stage_init (MetaWaylandStage *self) +{ + clutter_stage_set_user_resizable (CLUTTER_STAGE (self), FALSE); +} + +ClutterActor * +meta_wayland_stage_new (void) +{ + return g_object_new (META_TYPE_WAYLAND_STAGE, + "cursor-visible", FALSE, + NULL); +} diff --git a/src/wayland/meta-wayland-stage.h b/src/wayland/meta-wayland-stage.h new file mode 100644 index 0000000..4dcfb64 --- /dev/null +++ b/src/wayland/meta-wayland-stage.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2012 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_WAYLAND_STAGE_H +#define META_WAYLAND_STAGE_H + +#include <clutter/clutter.h> +#include <wayland-server.h> + +#include "window-private.h" + +G_BEGIN_DECLS + +#define META_TYPE_WAYLAND_STAGE (meta_wayland_stage_get_type ()) +#define META_WAYLAND_STAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WAYLAND_STAGE, MetaWaylandStage)) +#define META_WAYLAND_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WAYLAND_STAGE, MetaWaylandStageClass)) +#define META_IS_WAYLAND_STAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WAYLAND_STAGE)) +#define META_IS_WAYLAND_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WAYLAND_STAGE)) +#define META_WAYLAND_STAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WAYLAND_STAGE, MetaWaylandStageClass)) + +typedef struct _MetaWaylandStage MetaWaylandStage; +typedef struct _MetaWaylandStageClass MetaWaylandStageClass; + +struct _MetaWaylandStageClass +{ + ClutterStageClass parent_class; +}; + +struct _MetaWaylandStage +{ + ClutterStage parent; +}; + +GType meta_wayland_stage_get_type (void) G_GNUC_CONST; + +ClutterActor *meta_wayland_stage_new (void); + +G_END_DECLS + +#endif /* META_WAYLAND_STAGE_H */ diff --git a/src/wayland/meta-wayland-surface-private.h b/src/wayland/meta-wayland-surface-private.h new file mode 100644 index 0000000..9b882df --- /dev/null +++ b/src/wayland/meta-wayland-surface-private.h @@ -0,0 +1,32 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#ifndef META_WAYLAND_SURFACE_PRIVATE_H +#define META_WAYLAND_SURFACE_PRIVATE_H + +#include "meta-wayland-types.h" + +void meta_wayland_surface_commit (MetaWaylandSurface *surface); + +#endif /* META_WAYLAND_SURFACE_PRIVATE_H */ diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c new file mode 100644 index 0000000..a9aae35 --- /dev/null +++ b/src/wayland/meta-wayland-surface.c @@ -0,0 +1,1836 @@ +/* + * Wayland Support + * + * Copyright (C) 2012,2013 Intel Corporation + * 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <config.h> + +#include <clutter/clutter.h> +#include <clutter/wayland/clutter-wayland-compositor.h> +#include <clutter/wayland/clutter-wayland-surface.h> +#include <cogl/cogl-wayland-server.h> + +#include <glib.h> +#include <sys/time.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <unistd.h> + +#include <wayland-server.h> +#include "gtk-shell-server-protocol.h" +#include "xdg-shell-server-protocol.h" + +#include "meta-wayland-private.h" +#include "meta-xwayland-private.h" +#include "meta-wayland-stage.h" +#include "meta-wayland-seat.h" +#include "meta-wayland-keyboard.h" +#include "meta-wayland-pointer.h" +#include "meta-wayland-data-device.h" +#include "meta-wayland-surface-private.h" + +#include "meta-cursor-tracker-private.h" +#include "display-private.h" +#include "window-private.h" +#include <meta/types.h> +#include <meta/main.h> +#include "frame.h" + +#include "meta-surface-actor.h" +#include "meta-surface-actor-wayland.h" + +typedef enum +{ + META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE, + META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW +} MetaWaylandSubsurfacePlacement; + +typedef struct +{ + MetaWaylandSubsurfacePlacement placement; + MetaWaylandSurface *sibling; + struct wl_listener sibling_destroy_listener; +} MetaWaylandSubsurfacePlacementOp; + +static void +surface_set_buffer (MetaWaylandSurface *surface, + MetaWaylandBuffer *buffer) +{ + if (surface->buffer == buffer) + return; + + if (surface->buffer) + { + wl_list_remove (&surface->buffer_destroy_listener.link); + meta_wayland_buffer_unref (surface->buffer); + } + + surface->buffer = buffer; + + if (surface->buffer) + { + meta_wayland_buffer_ref (surface->buffer); + wl_signal_add (&surface->buffer->destroy_signal, &surface->buffer_destroy_listener); + } +} + +static void +surface_handle_buffer_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandSurface *surface = wl_container_of (listener, surface, buffer_destroy_listener); + + surface_set_buffer (surface, NULL); +} + +static void +surface_process_damage (MetaWaylandSurface *surface, + cairo_region_t *region) +{ + int i, n_rectangles = cairo_region_num_rectangles (region); + + for (i = 0; i < n_rectangles; i++) + { + cairo_rectangle_int_t rect; + cairo_region_get_rectangle (region, i, &rect); + meta_surface_actor_process_damage (surface->surface_actor, + rect.x, rect.y, rect.width, rect.height); + } +} + +static void +empty_region (cairo_region_t *region) +{ + cairo_rectangle_int_t rectangle = { 0, 0, 0, 0 }; + cairo_region_intersect_rectangle (region, &rectangle); +} + +static void +ensure_buffer_texture (MetaWaylandBuffer *buffer) +{ + CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + CoglError *catch_error = NULL; + CoglTexture *texture; + + texture = COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx, + buffer->resource, + &catch_error)); + if (!texture) + { + cogl_error_free (catch_error); + meta_warning ("Could not import pending buffer, ignoring commit\n"); + return; + } + + buffer->texture = texture; +} + +static gboolean +commit_attached_surface (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + /* wl_surface.attach */ + if (pending->newly_attached && surface->buffer != pending->buffer) + { + surface_set_buffer (surface, pending->buffer); + return TRUE; + } + else + return FALSE; +} + +static void +cursor_surface_commit (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + if (commit_attached_surface (surface, pending)) + meta_wayland_seat_update_cursor_surface (surface->compositor->seat); +} + +static gboolean +actor_surface_commit (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + MetaSurfaceActor *surface_actor = surface->surface_actor; + MetaWaylandBuffer *buffer = pending->buffer; + gboolean buffer_changed; + + buffer_changed = commit_attached_surface (surface, pending); + + if (buffer_changed && buffer) + { + ensure_buffer_texture (buffer); + meta_surface_actor_wayland_set_buffer (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), buffer); + } + + surface_process_damage (surface, pending->damage); + + if (pending->opaque_region) + meta_surface_actor_set_opaque_region (surface_actor, pending->opaque_region); + if (pending->input_region) + meta_surface_actor_set_input_region (surface_actor, pending->input_region); + + return buffer_changed; +} + +static void +toplevel_surface_commit (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + if (actor_surface_commit (surface, pending)) + { + MetaWindow *window = surface->window; + MetaWaylandBuffer *buffer = pending->buffer; + + meta_window_set_surface_mapped (window, buffer != NULL); + /* We resize X based surfaces according to X events */ + if (buffer != NULL && window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) + { + int new_width, new_height; + + new_width = cogl_texture_get_width (buffer->texture); + new_height = cogl_texture_get_height (buffer->texture); + + if (new_width != window->rect.width || + new_height != window->rect.height || + pending->dx != 0 || + pending->dy != 0) + meta_window_move_resize_wayland (window, new_width, new_height, pending->dx, pending->dy); + } + } + + if (pending->frame_extents_changed) + meta_window_set_custom_frame_extents (surface->window, &pending->frame_extents); +} + +static void +surface_handle_pending_buffer_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandDoubleBufferedState *state = + wl_container_of (listener, state, buffer_destroy_listener); + + state->buffer = NULL; +} + +static void +double_buffered_state_init (MetaWaylandDoubleBufferedState *state) +{ + state->newly_attached = FALSE; + state->buffer = NULL; + state->dx = 0; + state->dy = 0; + + state->damage = cairo_region_create (); + state->buffer_destroy_listener.notify = + surface_handle_pending_buffer_destroy; + wl_list_init (&state->frame_callback_list); + + state->frame_extents_changed = FALSE; +} + +static void +double_buffered_state_destroy (MetaWaylandDoubleBufferedState *state) +{ + MetaWaylandFrameCallback *cb, *next; + + g_clear_pointer (&state->damage, cairo_region_destroy); + g_clear_pointer (&state->input_region, cairo_region_destroy); + g_clear_pointer (&state->opaque_region, cairo_region_destroy); + + if (state->buffer) + wl_list_remove (&state->buffer_destroy_listener.link); + wl_list_for_each_safe (cb, next, &state->frame_callback_list, link) + wl_resource_destroy (cb->resource); +} + +static void +double_buffered_state_reset (MetaWaylandDoubleBufferedState *state) +{ + double_buffered_state_destroy (state); + double_buffered_state_init (state); +} + +static void +move_double_buffered_state (MetaWaylandDoubleBufferedState *from, + MetaWaylandDoubleBufferedState *to) +{ + if (from->buffer) + wl_list_remove (&from->buffer_destroy_listener.link); + + to->newly_attached = from->newly_attached; + from->newly_attached = FALSE; + + to->buffer = from->buffer; + from->buffer = NULL; + if (to->buffer) + wl_signal_add (&to->buffer->destroy_signal, &to->buffer_destroy_listener); + + to->dx = from->dx; + to->dy = from->dy; + from->dx = from->dy = 0; + + empty_region (to->damage); + cairo_region_union (to->damage, from->damage); + empty_region (from->damage); + + g_clear_pointer (&to->input_region, cairo_region_destroy); + g_clear_pointer (&to->opaque_region, cairo_region_destroy); + to->input_region = from->input_region; + to->opaque_region = from->opaque_region; + from->input_region = from->opaque_region = NULL; + + wl_list_init (&to->frame_callback_list); + wl_list_insert_list (&to->frame_callback_list, &from->frame_callback_list); + wl_list_init (&from->frame_callback_list); +} + +static void +subsurface_surface_commit (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + /* + * If the sub-surface is in synchronous mode, post-pone the commit of its + * state until the sub-surface parent commits. + * + * This is done by moving the various states (damage, input region, buffer + * etc.) from the buffered state pending commit to the sub-surface's pending + * buffered state. + * + * The sub-surface's pending buffered state will be committed to the + * associated surface when its parent surface is committed, or if the user + * issues a wl_subsurface.set_desync request. + */ + if (surface->sub.synchronous) + { + move_double_buffered_state (pending, &surface->sub.pending_surface_state); + } + else + { + if (actor_surface_commit (surface, pending)) + { + MetaSurfaceActor *surface_actor = surface->surface_actor; + MetaWaylandBuffer *buffer = pending->buffer; + float x, y; + + if (buffer != NULL) + clutter_actor_show (CLUTTER_ACTOR (surface_actor)); + else + clutter_actor_hide (CLUTTER_ACTOR (surface_actor)); + + clutter_actor_get_position (CLUTTER_ACTOR (surface_actor), &x, &y); + x += pending->dx; + y += pending->dy; + clutter_actor_set_position (CLUTTER_ACTOR (surface_actor), x, y); + } + } +} + +static void +subsurface_parent_surface_committed (MetaWaylandSurface *surface); + +static void +parent_surface_committed (gpointer data, gpointer user_data) +{ + subsurface_parent_surface_committed (data); +} + +static void +commit_double_buffered_state (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + MetaWaylandCompositor *compositor = surface->compositor; + + if (surface == compositor->seat->cursor_surface) + cursor_surface_commit (surface, pending); + else if (surface->window) + toplevel_surface_commit (surface, pending); + else if (surface->subsurface.resource) + subsurface_surface_commit (surface, pending); + else + { + /* Unknown surface type. In this case, it's most likely a XWayland + * surface that we haven't gotten the ClientMessage for yet. Make + * sure *not* to reset the double-buffered state or do anything too + * fancy. */ + return; + } + + g_list_foreach (surface->subsurfaces, + parent_surface_committed, + NULL); + + if (pending->buffer) + { + wl_list_remove (&pending->buffer_destroy_listener.link); + pending->buffer = NULL; + } + + /* wl_surface.frame */ + wl_list_insert_list (&compositor->frame_callbacks, &pending->frame_callback_list); + wl_list_init (&pending->frame_callback_list); + + double_buffered_state_reset (pending); +} + +void +meta_wayland_surface_commit (MetaWaylandSurface *surface) +{ + commit_double_buffered_state (surface, &surface->pending); +} + +static void +wl_surface_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +wl_surface_attach (struct wl_client *client, + struct wl_resource *surface_resource, + struct wl_resource *buffer_resource, + gint32 dx, gint32 dy) +{ + MetaWaylandSurface *surface = + wl_resource_get_user_data (surface_resource); + MetaWaylandBuffer *buffer; + + /* X11 unmanaged window */ + if (!surface) + return; + + if (buffer_resource) + buffer = meta_wayland_buffer_from_resource (buffer_resource); + else + buffer = NULL; + + /* Attach without commit in between does not send wl_buffer.release */ + if (surface->pending.buffer) + wl_list_remove (&surface->pending.buffer_destroy_listener.link); + + surface->pending.dx = dx; + surface->pending.dy = dy; + surface->pending.buffer = buffer; + surface->pending.newly_attached = TRUE; + + if (buffer) + wl_signal_add (&buffer->destroy_signal, + &surface->pending.buffer_destroy_listener); +} + +static void +wl_surface_damage (struct wl_client *client, + struct wl_resource *surface_resource, + gint32 x, + gint32 y, + gint32 width, + gint32 height) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + cairo_rectangle_int_t rectangle = { x, y, width, height }; + + /* X11 unmanaged window */ + if (!surface) + return; + + cairo_region_union_rectangle (surface->pending.damage, &rectangle); +} + +static void +destroy_frame_callback (struct wl_resource *callback_resource) +{ + MetaWaylandFrameCallback *callback = + wl_resource_get_user_data (callback_resource); + + wl_list_remove (&callback->link); + g_slice_free (MetaWaylandFrameCallback, callback); +} + +static void +wl_surface_frame (struct wl_client *client, + struct wl_resource *surface_resource, + guint32 callback_id) +{ + MetaWaylandFrameCallback *callback; + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + + /* X11 unmanaged window */ + if (!surface) + return; + + callback = g_slice_new0 (MetaWaylandFrameCallback); + callback->compositor = surface->compositor; + callback->resource = wl_resource_create (client, &wl_callback_interface, META_WL_CALLBACK_VERSION, callback_id); + wl_resource_set_implementation (callback->resource, NULL, callback, destroy_frame_callback); + + wl_list_insert (surface->pending.frame_callback_list.prev, &callback->link); +} + +static void +wl_surface_set_opaque_region (struct wl_client *client, + struct wl_resource *surface_resource, + struct wl_resource *region_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + + /* X11 unmanaged window */ + if (!surface) + return; + + g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy); + if (region_resource) + { + MetaWaylandRegion *region = wl_resource_get_user_data (region_resource); + surface->pending.opaque_region = cairo_region_copy (region->region); + } +} + +static void +wl_surface_set_input_region (struct wl_client *client, + struct wl_resource *surface_resource, + struct wl_resource *region_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + + /* X11 unmanaged window */ + if (!surface) + return; + + g_clear_pointer (&surface->pending.input_region, cairo_region_destroy); + if (region_resource) + { + MetaWaylandRegion *region = wl_resource_get_user_data (region_resource); + surface->pending.input_region = cairo_region_copy (region->region); + } +} + +static void +wl_surface_commit (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + /* X11 unmanaged window */ + if (!surface) + return; + + meta_wayland_surface_commit (surface); +} + +static void +wl_surface_set_buffer_transform (struct wl_client *client, + struct wl_resource *resource, + int32_t transform) +{ + g_warning ("TODO: support set_buffer_transform request"); +} + +static void +wl_surface_set_buffer_scale (struct wl_client *client, + struct wl_resource *resource, + int scale) +{ + if (scale != 1) + g_warning ("TODO: support set_buffer_scale request"); +} + +const struct wl_surface_interface meta_wayland_wl_surface_interface = { + wl_surface_destroy, + wl_surface_attach, + wl_surface_damage, + wl_surface_frame, + wl_surface_set_opaque_region, + wl_surface_set_input_region, + wl_surface_commit, + wl_surface_set_buffer_transform, + wl_surface_set_buffer_scale +}; + +void +meta_wayland_surface_set_window (MetaWaylandSurface *surface, + MetaWindow *window) +{ + gboolean has_window = (window != NULL); + + clutter_actor_set_reactive (CLUTTER_ACTOR (surface->surface_actor), has_window); + surface->window = window; +} + +static void +destroy_window (MetaWaylandSurface *surface) +{ + if (surface->window) + { + MetaDisplay *display = meta_get_display (); + guint32 timestamp = meta_display_get_current_time_roundtrip (display); + + meta_window_unmanage (surface->window, timestamp); + } + + g_assert (surface->window == NULL); +} + +static void +wl_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandCompositor *compositor = surface->compositor; + + /* If we still have a window at the time of destruction, that means that + * the client is disconnecting, as the resources are destroyed in a random + * order. Simply destroy the window in this case. */ + if (surface->window) + destroy_window (surface); + + compositor->surfaces = g_list_remove (compositor->surfaces, surface); + + surface_set_buffer (surface, NULL); + double_buffered_state_destroy (&surface->pending); + + g_object_unref (surface->surface_actor); + + if (surface->resource) + wl_resource_set_user_data (surface->resource, NULL); + g_slice_free (MetaWaylandSurface, surface); + + meta_wayland_compositor_repick (compositor); +} + +MetaWaylandSurface * +meta_wayland_surface_create (MetaWaylandCompositor *compositor, + struct wl_client *client, + guint32 id, + guint32 version) +{ + MetaWaylandSurface *surface = g_slice_new0 (MetaWaylandSurface); + + surface->compositor = compositor; + + surface->resource = wl_resource_create (client, &wl_surface_interface, version, id); + wl_resource_set_implementation (surface->resource, &meta_wayland_wl_surface_interface, surface, wl_surface_destructor); + + surface->buffer_destroy_listener.notify = surface_handle_buffer_destroy; + surface->surface_actor = g_object_ref_sink (meta_surface_actor_wayland_new (surface)); + + double_buffered_state_init (&surface->pending); + return surface; +} + +static void +destroy_surface_extension (MetaWaylandSurfaceExtension *extension) +{ + extension->resource = NULL; +} + +static int +get_resource_version (struct wl_resource *master_resource, + int max_version) +{ + return MIN (max_version, wl_resource_get_version (master_resource)); +} + +static gboolean +create_surface_extension (MetaWaylandSurfaceExtension *extension, + int max_version, + const struct wl_interface *interface, + const void *implementation, + wl_resource_destroy_func_t destructor, + MetaWaylandSurface *surface, + struct wl_resource *master_resource, + guint32 id) +{ + struct wl_client *client; + + if (extension->resource != NULL) + return FALSE; + + client = wl_resource_get_client (surface->resource); + extension->resource = wl_resource_create (client, interface, get_resource_version (master_resource, max_version), id); + wl_resource_set_implementation (extension->resource, implementation, surface, destructor); + + return TRUE; +} + +static void +xdg_shell_use_unstable_version (struct wl_client *client, + struct wl_resource *resource, + int32_t version) +{ + if (version != XDG_SHELL_VERSION_CURRENT) + g_warning ("Bad xdg_shell version: %d", version); +} + +static void +xdg_shell_pong (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial) +{ + MetaDisplay *display = meta_get_display (); + + meta_display_pong_for_serial (display, serial); +} + +static void +xdg_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + destroy_window (surface); + destroy_surface_extension (&surface->xdg_surface); +} + +static void +xdg_surface_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +xdg_surface_set_transient_for (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWindow *transient_for = NULL; + + if (parent_resource) + { + MetaWaylandSurface *parent_surface = wl_resource_get_user_data (parent_resource); + transient_for = parent_surface->window; + } + + meta_window_set_transient_for (surface->window, transient_for); +} + +static void +xdg_surface_set_margin (struct wl_client *client, + struct wl_resource *resource, + int32_t left_margin, + int32_t right_margin, + int32_t top_margin, + int32_t bottom_margin) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + surface->pending.frame_extents_changed = TRUE; + surface->pending.frame_extents.left = left_margin; + surface->pending.frame_extents.right = right_margin; + surface->pending.frame_extents.top = top_margin; + surface->pending.frame_extents.bottom = bottom_margin; +} + +static void +xdg_surface_set_title (struct wl_client *client, + struct wl_resource *resource, + const char *title) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_title (surface->window, title); +} + +static void +xdg_surface_set_app_id (struct wl_client *client, + struct wl_resource *resource, + const char *app_id) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_wm_class (surface->window, app_id, app_id); +} + +static gboolean +begin_grab_op_on_surface (MetaWaylandSurface *surface, + MetaWaylandSeat *seat, + MetaGrabOp grab_op) +{ + MetaWindow *window = surface->window; + + if (grab_op == META_GRAB_OP_NONE) + return FALSE; + + return meta_display_begin_grab_op (window->display, + window->screen, + window, + grab_op, + TRUE, /* pointer_already_grabbed */ + FALSE, /* frame_action */ + 1, /* button. XXX? */ + 0, /* modmask */ + meta_display_get_current_time_roundtrip (window->display), + wl_fixed_to_int (seat->pointer.grab_x), + wl_fixed_to_int (seat->pointer.grab_y)); +} + +static void +xdg_surface_move (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + guint32 serial) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + seat->pointer.focus_surface != surface) + return; + + begin_grab_op_on_surface (surface, seat, META_GRAB_OP_MOVING); +} + +static MetaGrabOp +grab_op_for_xdg_surface_resize_edge (int edge) +{ + switch (edge) + { + case XDG_SURFACE_RESIZE_EDGE_TOP_LEFT: + return META_GRAB_OP_RESIZING_NW; + case XDG_SURFACE_RESIZE_EDGE_TOP: + return META_GRAB_OP_RESIZING_N; + case XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT: + return META_GRAB_OP_RESIZING_NE; + case XDG_SURFACE_RESIZE_EDGE_RIGHT: + return META_GRAB_OP_RESIZING_E; + case XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT: + return META_GRAB_OP_RESIZING_SE; + case XDG_SURFACE_RESIZE_EDGE_BOTTOM: + return META_GRAB_OP_RESIZING_S; + case XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT: + return META_GRAB_OP_RESIZING_SW; + case XDG_SURFACE_RESIZE_EDGE_LEFT: + return META_GRAB_OP_RESIZING_W; + default: + g_warning ("invalid edge: %d", edge); + return META_GRAB_OP_NONE; + } +} + +static void +xdg_surface_resize (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + guint32 serial, + guint32 edges) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + seat->pointer.focus_surface != surface) + return; + + begin_grab_op_on_surface (surface, seat, grab_op_for_xdg_surface_resize_edge (edges)); +} + +static void +xdg_surface_set_output (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output) +{ + g_warning ("TODO: support xdg_surface.set_output"); +} + +static void +xdg_surface_request_change_state (struct wl_client *client, + struct wl_resource *resource, + uint32_t state_type, + uint32_t value, + uint32_t serial) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + surface->state_changed_serial = serial; + + switch (state_type) + { + case XDG_SURFACE_STATE_MAXIMIZED: + if (value) + meta_window_maximize (surface->window, META_MAXIMIZE_BOTH); + else + meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH); + break; + case XDG_SURFACE_STATE_FULLSCREEN: + if (value) + meta_window_make_fullscreen (surface->window); + else + meta_window_unmake_fullscreen (surface->window); + } +} + +static void +xdg_surface_ack_change_state (struct wl_client *client, + struct wl_resource *resource, + uint32_t state_type, + uint32_t value, + uint32_t serial) +{ + /* Do nothing for now. In the future, we'd imagine that + * we'd ignore attaches when we have a state pending that + * we haven't had the client ACK'd, to prevent a race + * condition when we have an in-flight attach when the + * client gets the new state. */ +} + +static void +xdg_surface_set_minimized (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_minimize (surface->window); +} + +static const struct xdg_surface_interface meta_wayland_xdg_surface_interface = { + xdg_surface_destroy, + xdg_surface_set_transient_for, + xdg_surface_set_margin, + xdg_surface_set_title, + xdg_surface_set_app_id, + xdg_surface_move, + xdg_surface_resize, + xdg_surface_set_output, + xdg_surface_request_change_state, + xdg_surface_ack_change_state, + xdg_surface_set_minimized, +}; + +static void +xdg_shell_get_xdg_surface (struct wl_client *client, + struct wl_resource *resource, + guint32 id, + struct wl_resource *surface_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWindow *window; + + if (!create_surface_extension (&surface->xdg_surface, + META_XDG_SURFACE_VERSION, + &xdg_surface_interface, + &meta_wayland_xdg_surface_interface, + xdg_surface_destructor, + surface, resource, id)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "xdg_shell::get_xdg_surface already requested"); + return; + } + + window = meta_window_wayland_new (meta_get_display (), surface); + meta_wayland_surface_set_window (surface, window); +} + +static void +xdg_popup_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + destroy_window (surface); + destroy_surface_extension (&surface->xdg_popup); +} + +static void +xdg_popup_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = { + xdg_popup_destroy, +}; + +static void +xdg_shell_get_xdg_popup (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource, + struct wl_resource *parent_resource, + struct wl_resource *seat_resource, + uint32_t serial, + int32_t x, + int32_t y, + uint32_t flags) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWindow *window; + + if (parent_surf == NULL || parent_surf->window == NULL) + return; + + if (!create_surface_extension (&surface->xdg_popup, + META_XDG_POPUP_VERSION, + &xdg_popup_interface, + &meta_wayland_xdg_popup_interface, + xdg_popup_destructor, + surface, resource, id)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "xdg_shell::get_xdg_popup already requested"); + return; + } + + window = meta_window_wayland_new (meta_get_display (), surface); + window->rect.x = parent_surf->window->rect.x + x; + window->rect.y = parent_surf->window->rect.y + y; + window->showing_for_first_time = FALSE; + window->placed = TRUE; + meta_window_set_transient_for (window, parent_surf->window); + meta_window_set_type (window, META_WINDOW_DROPDOWN_MENU); + + meta_wayland_surface_set_window (surface, window); + + meta_wayland_pointer_start_popup_grab (&seat->pointer, surface); +} + +static const struct xdg_shell_interface meta_wayland_xdg_shell_interface = { + xdg_shell_use_unstable_version, + xdg_shell_get_xdg_surface, + xdg_shell_get_xdg_popup, + xdg_shell_pong, +}; + +typedef struct { + struct wl_resource *resource; + struct wl_listener client_destroy_listener; +} XdgShell; + +static void +xdg_shell_handle_client_destroy (struct wl_listener *listener, void *data) +{ + XdgShell *xdg_shell = wl_container_of (listener, xdg_shell, client_destroy_listener); + g_slice_free (XdgShell, xdg_shell); +} + +static struct wl_resource * +get_xdg_shell_for_client (struct wl_client *client) +{ + struct wl_listener *listener; + XdgShell *xdg_shell; + + listener = wl_client_get_destroy_listener (client, xdg_shell_handle_client_destroy); + + /* No xdg_shell has been bound for this client */ + if (listener == NULL) + return NULL; + + xdg_shell = wl_container_of (listener, xdg_shell, client_destroy_listener); + return xdg_shell->resource; +} + +static void +bind_xdg_shell (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + struct wl_resource *resource; + XdgShell *xdg_shell; + + if (version != 1) + { + g_warning ("using xdg-shell without stable version 1\n"); + return; + } + + xdg_shell = g_slice_new (XdgShell); + + resource = wl_resource_create (client, &xdg_shell_interface, 1, id); + wl_resource_set_implementation (resource, &meta_wayland_xdg_shell_interface, data, NULL); + xdg_shell->resource = wl_resource_create (client, &xdg_shell_interface, 1, id); + wl_resource_set_implementation (xdg_shell->resource, &meta_wayland_xdg_shell_interface, data, NULL); + + xdg_shell->client_destroy_listener.notify = xdg_shell_handle_client_destroy; + wl_client_add_destroy_listener (client, &xdg_shell->client_destroy_listener); +} + +static void +wl_shell_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + destroy_surface_extension (&surface->wl_shell_surface); +} + +static void +wl_shell_surface_pong (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial) +{ + MetaDisplay *display = meta_get_display (); + + meta_display_pong_for_serial (display, serial); +} + +static void +wl_shell_surface_move (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + seat->pointer.focus_surface != surface) + return; + + begin_grab_op_on_surface (surface, seat, META_GRAB_OP_MOVING); +} + +static MetaGrabOp +grab_op_for_wl_shell_surface_resize_edge (int edge) +{ + switch (edge) + { + case WL_SHELL_SURFACE_RESIZE_TOP_LEFT: + return META_GRAB_OP_RESIZING_NW; + case WL_SHELL_SURFACE_RESIZE_TOP: + return META_GRAB_OP_RESIZING_N; + case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: + return META_GRAB_OP_RESIZING_NE; + case WL_SHELL_SURFACE_RESIZE_RIGHT: + return META_GRAB_OP_RESIZING_E; + case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: + return META_GRAB_OP_RESIZING_SE; + case WL_SHELL_SURFACE_RESIZE_BOTTOM: + return META_GRAB_OP_RESIZING_S; + case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: + return META_GRAB_OP_RESIZING_SW; + case WL_SHELL_SURFACE_RESIZE_LEFT: + return META_GRAB_OP_RESIZING_W; + default: + g_warning ("invalid edge: %d", edge); + return META_GRAB_OP_NONE; + } +} + +static void +wl_shell_surface_resize (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial, + uint32_t edges) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + seat->pointer.focus_surface != surface) + return; + + begin_grab_op_on_surface (surface, seat, grab_op_for_wl_shell_surface_resize_edge (edges)); +} + +typedef enum { + SURFACE_STATE_TOPLEVEL, + SURFACE_STATE_FULLSCREEN, + SURFACE_STATE_MAXIMIZED, +} SurfaceState; + +static void +wl_shell_surface_set_state (MetaWaylandSurface *surface, + SurfaceState state) +{ + if (state == SURFACE_STATE_FULLSCREEN) + meta_window_make_fullscreen (surface->window); + else + meta_window_unmake_fullscreen (surface->window); + + if (state == SURFACE_STATE_MAXIMIZED) + meta_window_maximize (surface->window, META_MAXIMIZE_BOTH); + else + meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH); +} + +static void +wl_shell_surface_set_toplevel (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL); +} + +static void +wl_shell_surface_set_transient (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent_resource, + int32_t x, + int32_t y, + uint32_t flags) +{ + MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL); + + meta_window_set_transient_for (surface->window, parent_surf->window); + meta_window_move (surface->window, FALSE, + parent_surf->window->rect.x + x, + parent_surf->window->rect.y + y); + surface->window->placed = TRUE; +} + +static void +wl_shell_surface_set_fullscreen (struct wl_client *client, + struct wl_resource *resource, + uint32_t method, + uint32_t framerate, + struct wl_resource *output) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_FULLSCREEN); +} + +static void +wl_shell_surface_set_popup (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial, + struct wl_resource *parent_resource, + int32_t x, + int32_t y, + uint32_t flags) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL); + + meta_window_set_transient_for (surface->window, parent_surf->window); + meta_window_move (surface->window, FALSE, + parent_surf->window->rect.x + x, + parent_surf->window->rect.y + y); + surface->window->placed = TRUE; + + meta_wayland_pointer_start_popup_grab (&seat->pointer, surface); +} + +static void +wl_shell_surface_set_maximized (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_MAXIMIZED); +} + +static void +wl_shell_surface_set_title (struct wl_client *client, + struct wl_resource *resource, + const char *title) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_title (surface->window, title); +} + +static void +wl_shell_surface_set_class (struct wl_client *client, + struct wl_resource *resource, + const char *class_) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_wm_class (surface->window, class_, class_); +} + +static const struct wl_shell_surface_interface meta_wayland_wl_shell_surface_interface = { + wl_shell_surface_pong, + wl_shell_surface_move, + wl_shell_surface_resize, + wl_shell_surface_set_toplevel, + wl_shell_surface_set_transient, + wl_shell_surface_set_fullscreen, + wl_shell_surface_set_popup, + wl_shell_surface_set_maximized, + wl_shell_surface_set_title, + wl_shell_surface_set_class, +}; + +static void +wl_shell_get_shell_surface (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWindow *window; + + if (!create_surface_extension (&surface->wl_shell_surface, + META_WL_SHELL_SURFACE_VERSION, + &wl_shell_surface_interface, + &meta_wayland_wl_shell_surface_interface, + wl_shell_surface_destructor, + surface, resource, id)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "wl_shell::get_shell_surface already requested"); + return; + } + + window = meta_window_wayland_new (meta_get_display (), surface); + meta_wayland_surface_set_window (surface, window); +} + +static const struct wl_shell_interface meta_wayland_wl_shell_interface = { + wl_shell_get_shell_surface, +}; + +static void +bind_wl_shell (struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_shell_interface, + MIN (META_WL_SHELL_VERSION, version), id); + wl_resource_set_implementation (resource, &meta_wayland_wl_shell_interface, data, NULL); +} + +static void +gtk_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + destroy_surface_extension (&surface->gtk_surface); +} + +static void +set_dbus_properties (struct wl_client *client, + struct wl_resource *resource, + const char *application_id, + const char *app_menu_path, + const char *menubar_path, + const char *window_object_path, + const char *application_object_path, + const char *unique_bus_name) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + /* Broken client, let it die instead of us */ + if (!surface->window) + { + meta_warning ("meta-wayland-surface: set_dbus_properties called with invalid window!\n"); + return; + } + + meta_window_set_gtk_dbus_properties (surface->window, + application_id, + unique_bus_name, + app_menu_path, + menubar_path, + application_object_path, + window_object_path); +} + +static const struct gtk_surface_interface meta_wayland_gtk_surface_interface = { + set_dbus_properties +}; + +static void +get_gtk_surface (struct wl_client *client, + struct wl_resource *resource, + guint32 id, + struct wl_resource *surface_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + + if (!create_surface_extension (&surface->gtk_surface, + META_GTK_SURFACE_VERSION, + >k_surface_interface, + &meta_wayland_gtk_surface_interface, + gtk_surface_destructor, + surface, resource, id)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "gtk_shell::get_gtk_surface already requested"); + return; + } +} + +static const struct gtk_shell_interface meta_wayland_gtk_shell_interface = { + get_gtk_surface +}; + +static void +bind_gtk_shell (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, >k_shell_interface, + MIN (META_GTK_SHELL_VERSION, version), id); + wl_resource_set_implementation (resource, &meta_wayland_gtk_shell_interface, data, NULL); + + /* FIXME: ask the plugin */ + gtk_shell_send_capabilities (resource, GTK_SHELL_CAPABILITY_GLOBAL_APP_MENU); +} + +static void +subsurface_parent_surface_committed (MetaWaylandSurface *surface) +{ + MetaWaylandDoubleBufferedState *pending_surface_state = &surface->sub.pending_surface_state; + + if (surface->sub.pending_pos) + { + clutter_actor_set_position (CLUTTER_ACTOR (surface->surface_actor), + surface->sub.pending_x, + surface->sub.pending_y); + surface->sub.pending_pos = FALSE; + } + + if (surface->sub.pending_placement_ops) + { + GSList *it; + for (it = surface->sub.pending_placement_ops; it; it = it->next) + { + MetaWaylandSubsurfacePlacementOp *op = it->data; + ClutterActor *surface_actor; + ClutterActor *parent_actor; + ClutterActor *sibling_actor; + + if (!op->sibling) + { + g_slice_free (MetaWaylandSubsurfacePlacementOp, op); + continue; + } + + surface_actor = CLUTTER_ACTOR (surface->surface_actor); + parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->sub.parent)); + sibling_actor = CLUTTER_ACTOR (op->sibling->surface_actor); + + switch (op->placement) + { + case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE: + clutter_actor_set_child_above_sibling (parent_actor, surface_actor, sibling_actor); + break; + case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW: + clutter_actor_set_child_below_sibling (parent_actor, surface_actor, sibling_actor); + break; + } + + wl_list_remove (&op->sibling_destroy_listener.link); + g_slice_free (MetaWaylandSubsurfacePlacementOp, op); + } + + g_slist_free (surface->sub.pending_placement_ops); + surface->sub.pending_placement_ops = NULL; + } + + if (surface->sub.synchronous) + commit_double_buffered_state (surface, pending_surface_state); +} + +static void +unparent_actor (MetaWaylandSurface *surface) +{ + ClutterActor *parent_actor; + parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->surface_actor)); + clutter_actor_remove_child (parent_actor, CLUTTER_ACTOR (surface->surface_actor)); +} + +static void +wl_subsurface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (surface->sub.parent) + { + wl_list_remove (&surface->sub.parent_destroy_listener.link); + surface->sub.parent->subsurfaces = + g_list_remove (surface->sub.parent->subsurfaces, surface); + unparent_actor (surface); + surface->sub.parent = NULL; + } + + double_buffered_state_destroy (&surface->sub.pending_surface_state); + destroy_surface_extension (&surface->subsurface); +} + +static void +wl_subsurface_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +wl_subsurface_set_position (struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + surface->sub.pending_x = x; + surface->sub.pending_y = y; + surface->sub.pending_pos = TRUE; +} + +static gboolean +is_valid_sibling (MetaWaylandSurface *surface, MetaWaylandSurface *sibling) +{ + if (surface->sub.parent == sibling) + return TRUE; + if (surface->sub.parent == sibling->sub.parent) + return TRUE; + return FALSE; +} + +static void +subsurface_handle_pending_sibling_destroyed (struct wl_listener *listener, void *data) +{ + MetaWaylandSubsurfacePlacementOp *op = + wl_container_of (listener, op, sibling_destroy_listener); + + op->sibling = NULL; +} + +static void +queue_subsurface_placement (MetaWaylandSurface *surface, + MetaWaylandSurface *sibling, + MetaWaylandSubsurfacePlacement placement) +{ + MetaWaylandSubsurfacePlacementOp *op = + g_slice_new (MetaWaylandSubsurfacePlacementOp); + + op->placement = placement; + op->sibling = sibling; + op->sibling_destroy_listener.notify = + subsurface_handle_pending_sibling_destroyed; + wl_resource_add_destroy_listener (sibling->resource, + &op->sibling_destroy_listener); + + surface->sub.pending_placement_ops = + g_slist_append (surface->sub.pending_placement_ops, op); +} + +static void +wl_subsurface_place_above (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *sibling_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource); + + if (!is_valid_sibling (surface, sibling)) + { + wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE, + "wl_subsurface::place_above: wl_surface@%d is " + "not a valid parent or sibling", + wl_resource_get_id (sibling->resource)); + return; + } + + queue_subsurface_placement (surface, + sibling, + META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE); +} + +static void +wl_subsurface_place_below (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *sibling_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource); + + if (!is_valid_sibling (surface, sibling)) + { + wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE, + "wl_subsurface::place_below: wl_surface@%d is " + "not a valid parent or sibling", + wl_resource_get_id (sibling->resource)); + return; + } + + queue_subsurface_placement (surface, + sibling, + META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW); +} + +static void +wl_subsurface_set_sync (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + surface->sub.synchronous = TRUE; +} + +static void +wl_subsurface_set_desync (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (surface->sub.synchronous) + subsurface_parent_surface_committed (surface); + + surface->sub.synchronous = FALSE; +} + +static const struct wl_subsurface_interface meta_wayland_subsurface_interface = { + wl_subsurface_destroy, + wl_subsurface_set_position, + wl_subsurface_place_above, + wl_subsurface_place_below, + wl_subsurface_set_sync, + wl_subsurface_set_desync, +}; + +static void +wl_subcompositor_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +surface_handle_parent_surface_destroyed (struct wl_listener *listener, + void *data) +{ + MetaWaylandSurface *surface = wl_container_of (listener, + surface, + sub.parent_destroy_listener); + + surface->sub.parent = NULL; + unparent_actor (surface); +} + +static void +wl_subcompositor_get_subsurface (struct wl_client *client, + struct wl_resource *resource, + guint32 id, + struct wl_resource *surface_resource, + struct wl_resource *parent_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandSurface *parent = wl_resource_get_user_data (parent_resource); + + if (!create_surface_extension (&surface->subsurface, + META_GTK_SURFACE_VERSION, + &wl_subsurface_interface, + &meta_wayland_subsurface_interface, + wl_subsurface_destructor, + surface, resource, id)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "wl_subcompositor::get_subsurface already requested"); + return; + } + + double_buffered_state_init (&surface->sub.pending_surface_state); + surface->sub.parent = parent; + surface->sub.parent_destroy_listener.notify = + surface_handle_parent_surface_destroyed; + wl_resource_add_destroy_listener (parent->resource, + &surface->sub.parent_destroy_listener); + parent->subsurfaces = g_list_append (parent->subsurfaces, surface); + + clutter_actor_add_child (CLUTTER_ACTOR (parent->surface_actor), + CLUTTER_ACTOR (surface->surface_actor)); +} + +static const struct wl_subcompositor_interface meta_wayland_subcompositor_interface = { + wl_subcompositor_destroy, + wl_subcompositor_get_subsurface, +}; + +static void +bind_subcompositor (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_subcompositor_interface, + MIN (META_WL_SUBCOMPOSITOR_VERSION, version), id); + wl_resource_set_implementation (resource, &meta_wayland_subcompositor_interface, data, NULL); +} + +void +meta_wayland_init_shell (MetaWaylandCompositor *compositor) +{ + if (wl_global_create (compositor->wayland_display, + &xdg_shell_interface, 1, + compositor, bind_xdg_shell) == NULL) + g_error ("Failed to register a global xdg-shell object"); + + if (wl_global_create (compositor->wayland_display, + &wl_shell_interface, 1, + compositor, bind_wl_shell) == NULL) + g_error ("Failed to register a global wl-shell object"); + + if (wl_global_create (compositor->wayland_display, + >k_shell_interface, + META_GTK_SHELL_VERSION, + compositor, bind_gtk_shell) == NULL) + g_error ("Failed to register a global gtk-shell object"); + + if (wl_global_create (compositor->wayland_display, + &wl_subcompositor_interface, + META_WL_SUBCOMPOSITOR_VERSION, + compositor, bind_subcompositor) == NULL) + g_error ("Failed to register a global wl-subcompositor object"); +} + +void +meta_wayland_surface_configure_notify (MetaWaylandSurface *surface, + int new_width, + int new_height) +{ + if (surface->xdg_surface.resource) + xdg_surface_send_configure (surface->xdg_surface.resource, + new_width, new_height); + else if (surface->wl_shell_surface.resource) + wl_shell_surface_send_configure (surface->wl_shell_surface.resource, + 0, new_width, new_height); +} + +static void +send_change_state (MetaWaylandSurface *surface, + uint32_t state_type, + uint32_t value) +{ + if (surface->xdg_surface.resource) + { + uint32_t serial; + + if (surface->state_changed_serial != 0) + { + serial = surface->state_changed_serial; + surface->state_changed_serial = 0; + } + else + { + struct wl_client *client = wl_resource_get_client (surface->xdg_surface.resource); + struct wl_display *display = wl_client_get_display (client); + serial = wl_display_next_serial (display); + } + + xdg_surface_send_change_state (surface->xdg_surface.resource, state_type, value, serial); + } +} + +void +meta_wayland_surface_send_maximized (MetaWaylandSurface *surface) +{ + send_change_state (surface, XDG_SURFACE_STATE_MAXIMIZED, TRUE); +} + +void +meta_wayland_surface_send_unmaximized (MetaWaylandSurface *surface) +{ + send_change_state (surface, XDG_SURFACE_STATE_MAXIMIZED, FALSE); +} + +void +meta_wayland_surface_send_fullscreened (MetaWaylandSurface *surface) +{ + send_change_state (surface, XDG_SURFACE_STATE_FULLSCREEN, TRUE); +} + +void +meta_wayland_surface_send_unfullscreened (MetaWaylandSurface *surface) +{ + send_change_state (surface, XDG_SURFACE_STATE_FULLSCREEN, FALSE); +} + +void +meta_wayland_surface_activated (MetaWaylandSurface *surface) +{ + if (surface->xdg_surface.resource) + xdg_surface_send_activated (surface->xdg_surface.resource); +} + +void +meta_wayland_surface_deactivated (MetaWaylandSurface *surface) +{ + if (surface->xdg_surface.resource) + xdg_surface_send_deactivated (surface->xdg_surface.resource); +} + +void +meta_wayland_surface_ping (MetaWaylandSurface *surface, + guint32 serial) +{ + if (surface->xdg_surface.resource) + { + struct wl_client *client = wl_resource_get_client (surface->resource); + struct wl_resource *xdg_shell = get_xdg_shell_for_client (client); + + if (xdg_shell == NULL) + { + g_warning ("Trying to ping a surface without an xdg_shell bound. How does this happen?"); + return; + } + + xdg_shell_send_ping (xdg_shell, serial); + } + else if (surface->wl_shell_surface.resource) + { + wl_shell_surface_send_ping (surface->wl_shell_surface.resource, serial); + } +} + +void +meta_wayland_surface_delete (MetaWaylandSurface *surface) +{ + if (surface->xdg_surface.resource) + xdg_surface_send_delete (surface->xdg_surface.resource); +} + +void +meta_wayland_surface_popup_done (MetaWaylandSurface *surface) +{ + struct wl_client *client = wl_resource_get_client (surface->resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t serial = wl_display_next_serial (display); + + if (surface->xdg_popup.resource) + xdg_popup_send_popup_done (surface->xdg_popup.resource, serial); + else if (surface->wl_shell_surface.resource) + wl_shell_surface_send_popup_done (surface->wl_shell_surface.resource); +} diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h new file mode 100644 index 0000000..25fe83c --- /dev/null +++ b/src/wayland/meta-wayland-surface.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_WAYLAND_SURFACE_H +#define META_WAYLAND_SURFACE_H + +#include <wayland-server.h> +#include <xkbcommon/xkbcommon.h> +#include <clutter/clutter.h> + +#include <glib.h> +#include <cairo.h> + +#include <meta/meta-cursor-tracker.h> +#include "meta-wayland-types.h" +#include "meta-surface-actor.h" + +struct _MetaWaylandBuffer +{ + struct wl_resource *resource; + struct wl_signal destroy_signal; + struct wl_listener destroy_listener; + + CoglTexture *texture; + uint32_t ref_count; +}; + +typedef struct +{ + /* wl_surface.attach */ + gboolean newly_attached; + MetaWaylandBuffer *buffer; + struct wl_listener buffer_destroy_listener; + int32_t dx; + int32_t dy; + + /* wl_surface.damage */ + cairo_region_t *damage; + + cairo_region_t *input_region; + cairo_region_t *opaque_region; + + /* wl_surface.frame */ + struct wl_list frame_callback_list; + + gboolean frame_extents_changed; + GtkBorder frame_extents; +} MetaWaylandDoubleBufferedState; + +typedef struct +{ + struct wl_resource *resource; +} MetaWaylandSurfaceExtension; + +struct _MetaWaylandSurface +{ + struct wl_resource *resource; + MetaWaylandCompositor *compositor; + MetaSurfaceActor *surface_actor; + MetaWindow *window; + MetaWaylandSurfaceExtension xdg_surface; + MetaWaylandSurfaceExtension xdg_popup; + MetaWaylandSurfaceExtension wl_shell_surface; + MetaWaylandSurfaceExtension gtk_surface; + MetaWaylandSurfaceExtension subsurface; + + MetaWaylandBuffer *buffer; + struct wl_listener buffer_destroy_listener; + + GList *subsurfaces; + + struct { + MetaWaylandSurface *parent; + struct wl_listener parent_destroy_listener; + + gboolean synchronous; + MetaWaylandDoubleBufferedState pending_surface_state; + + int32_t pending_x; + int32_t pending_y; + gboolean pending_pos; + GSList *pending_placement_ops; + } sub; + + uint32_t state_changed_serial; + + /* All the pending state, that wl_surface.commit will apply. */ + MetaWaylandDoubleBufferedState pending; +}; + +void meta_wayland_init_shell (MetaWaylandCompositor *compositor); + +MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *compositor, + struct wl_client *client, + guint32 id, + guint32 version); + +void meta_wayland_surface_set_window (MetaWaylandSurface *surface, + MetaWindow *window); + +void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface, + int width, + int height); +void meta_wayland_surface_send_maximized (MetaWaylandSurface *surface); +void meta_wayland_surface_send_unmaximized (MetaWaylandSurface *surface); +void meta_wayland_surface_send_fullscreened (MetaWaylandSurface *surface); +void meta_wayland_surface_send_unfullscreened (MetaWaylandSurface *surface); + +void meta_wayland_surface_activated (MetaWaylandSurface *surface); +void meta_wayland_surface_deactivated (MetaWaylandSurface *surface); + +void meta_wayland_surface_ping (MetaWaylandSurface *surface, + guint32 serial); +void meta_wayland_surface_delete (MetaWaylandSurface *surface); + +void meta_wayland_surface_popup_done (MetaWaylandSurface *surface); + + +#endif diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h new file mode 100644 index 0000000..adecb05 --- /dev/null +++ b/src/wayland/meta-wayland-types.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_WAYLAND_TYPES_H +#define META_WAYLAND_TYPES_H + +typedef struct _MetaWaylandCompositor MetaWaylandCompositor; + +typedef struct _MetaWaylandSeat MetaWaylandSeat; +typedef struct _MetaWaylandPointer MetaWaylandPointer; +typedef struct _MetaWaylandPointerGrab MetaWaylandPointerGrab; +typedef struct _MetaWaylandPointerGrabInterface MetaWaylandPointerGrabInterface; +typedef struct _MetaWaylandKeyboard MetaWaylandKeyboard; +typedef struct _MetaWaylandKeyboardGrab MetaWaylandKeyboardGrab; +typedef struct _MetaWaylandKeyboardGrabInterface MetaWaylandKeyboardGrabInterface; +typedef struct _MetaWaylandDataOffer MetaWaylandDataOffer; +typedef struct _MetaWaylandDataSource MetaWaylandDataSource; + +typedef struct _MetaWaylandBuffer MetaWaylandBuffer; +typedef struct _MetaWaylandBufferReference MetaWaylandBufferReference; + +typedef struct _MetaWaylandSurface MetaWaylandSurface; + +#endif diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h new file mode 100644 index 0000000..d599908 --- /dev/null +++ b/src/wayland/meta-wayland-versions.h @@ -0,0 +1,66 @@ +/* + * Wayland Support + * + * Copyright (C) 2012,2013 Intel Corporation + * 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_WAYLAND_VERSIONS_H +#define META_WAYLAND_VERSIONS_H + +/* Protocol objects, will never change version */ +/* #define META_WL_DISPLAY_VERSION 1 */ +/* #define META_WL_REGISTRY_VERSION 1 */ +#define META_WL_CALLBACK_VERSION 1 + +/* Not handled by mutter-wayland directly */ +/* #define META_WL_SHM_VERSION 1 */ +/* #define META_WL_SHM_POOL_VERSION 1 */ +/* #define META_WL_DRM_VERSION 1 */ +/* #define META_WL_BUFFER_VERSION 1 */ + +/* Global/master objects (version exported by wl_registry and negotiated through bind) */ +#define META_WL_COMPOSITOR_VERSION 3 +#define META_WL_DATA_DEVICE_MANAGER_VERSION 1 +#define META_WL_SHELL_VERSION 1 +#define META_WL_SEAT_VERSION 3 +#define META_WL_OUTPUT_VERSION 2 +#define META_XSERVER_VERSION 1 +#define META_GTK_SHELL_VERSION 1 +#define META_WL_SUBCOMPOSITOR_VERSION 1 + +/* Slave objects (version inherited from a master object) */ +#define META_WL_DATA_OFFER_VERSION 1 /* from wl_data_device */ +#define META_WL_DATA_SOURCE_VERSION 1 /* from wl_data_device */ +#define META_WL_DATA_DEVICE_VERSION 1 /* from wl_data_device_manager */ +#define META_WL_SURFACE_VERSION 3 /* from wl_compositor */ +#define META_WL_POINTER_VERSION 3 /* from wl_seat */ +#define META_WL_KEYBOARD_VERSION 3 /* from wl_seat */ +#define META_WL_TOUCH_VERSION 0 /* from wl_seat; wl_touch not supported */ +#define META_WL_REGION_VERSION 1 /* from wl_compositor */ +#define META_XDG_SURFACE_VERSION 1 /* from xdg_shell */ +#define META_XDG_POPUP_VERSION 1 /* from xdg_shell */ +#define META_WL_SHELL_SURFACE_VERSION 1 /* from wl_shell */ +#define META_GTK_SURFACE_VERSION 1 /* from gtk_shell */ +#define META_WL_SUBSURFACE_VERSION 1 /* from wl_subcompositor */ + +/* The first version to implement a specific event */ +#define META_WL_SEAT_HAS_NAME 2 +#define META_WL_OUTPUT_HAS_DONE 2 + +#endif diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c new file mode 100644 index 0000000..1d9be56 --- /dev/null +++ b/src/wayland/meta-wayland.c @@ -0,0 +1,683 @@ +/* + * Wayland Support + * + * Copyright (C) 2012,2013 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <config.h> + +#include <clutter/clutter.h> +#include <clutter/wayland/clutter-wayland-compositor.h> +#include <clutter/wayland/clutter-wayland-surface.h> + +#include <glib.h> +#include <sys/time.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <unistd.h> + +#include <wayland-server.h> + +#include "backends/meta-backend.h" + +#include "meta-wayland-private.h" +#include "meta-xwayland-private.h" +#include "meta-wayland-stage.h" +#include "meta-window-actor-private.h" +#include "meta-wayland-seat.h" +#include "meta-wayland-keyboard.h" +#include "meta-wayland-pointer.h" +#include "meta-wayland-data-device.h" +#include "meta-cursor-tracker-private.h" +#include "display-private.h" +#include "window-private.h" +#include <meta/types.h> +#include <meta/main.h> +#include "frame.h" +#include "meta-monitor-manager.h" + +static MetaWaylandCompositor _meta_wayland_compositor; + +MetaWaylandCompositor * +meta_wayland_compositor_get_default (void) +{ + return &_meta_wayland_compositor; +} + +static guint32 +get_time (void) +{ + struct timeval tv; + gettimeofday (&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +static gboolean +wayland_event_source_prepare (GSource *base, int *timeout) +{ + WaylandEventSource *source = (WaylandEventSource *)base; + + *timeout = -1; + + wl_display_flush_clients (source->display); + + return FALSE; +} + +static gboolean +wayland_event_source_check (GSource *base) +{ + WaylandEventSource *source = (WaylandEventSource *)base; + return source->pfd.revents; +} + +static gboolean +wayland_event_source_dispatch (GSource *base, + GSourceFunc callback, + void *data) +{ + WaylandEventSource *source = (WaylandEventSource *)base; + struct wl_event_loop *loop = wl_display_get_event_loop (source->display); + + wl_event_loop_dispatch (loop, 0); + + return TRUE; +} + +static GSourceFuncs wayland_event_source_funcs = +{ + wayland_event_source_prepare, + wayland_event_source_check, + wayland_event_source_dispatch, + NULL +}; + +static GSource * +wayland_event_source_new (struct wl_display *display) +{ + WaylandEventSource *source; + struct wl_event_loop *loop = wl_display_get_event_loop (display); + + source = (WaylandEventSource *) g_source_new (&wayland_event_source_funcs, + sizeof (WaylandEventSource)); + source->display = display; + source->pfd.fd = wl_event_loop_get_fd (loop); + source->pfd.events = G_IO_IN | G_IO_ERR; + g_source_add_poll (&source->source, &source->pfd); + + return &source->source; +} + +static void +meta_wayland_buffer_destroy_handler (struct wl_listener *listener, + void *data) +{ + MetaWaylandBuffer *buffer = + wl_container_of (listener, buffer, destroy_listener); + + wl_signal_emit (&buffer->destroy_signal, buffer); + g_slice_free (MetaWaylandBuffer, buffer); +} + +void +meta_wayland_buffer_ref (MetaWaylandBuffer *buffer) +{ + buffer->ref_count++; +} + +void +meta_wayland_buffer_unref (MetaWaylandBuffer *buffer) +{ + buffer->ref_count--; + if (buffer->ref_count == 0) + { + g_clear_pointer (&buffer->texture, cogl_object_unref); + wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE); + } +} + +MetaWaylandBuffer * +meta_wayland_buffer_from_resource (struct wl_resource *resource) +{ + MetaWaylandBuffer *buffer; + struct wl_listener *listener; + + listener = + wl_resource_get_destroy_listener (resource, + meta_wayland_buffer_destroy_handler); + + if (listener) + { + buffer = wl_container_of (listener, buffer, destroy_listener); + } + else + { + buffer = g_slice_new0 (MetaWaylandBuffer); + + buffer->resource = resource; + wl_signal_init (&buffer->destroy_signal); + buffer->destroy_listener.notify = meta_wayland_buffer_destroy_handler; + wl_resource_add_destroy_listener (resource, &buffer->destroy_listener); + } + + return buffer; +} + +void +meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor, + MetaWindow *window) +{ + MetaWaylandSurface *surface = window ? window->surface : NULL; + + meta_wayland_keyboard_set_focus (&compositor->seat->keyboard, + surface); + meta_wayland_data_device_set_keyboard_focus (compositor->seat); +} + +void +meta_wayland_compositor_repick (MetaWaylandCompositor *compositor) +{ + meta_wayland_seat_repick (compositor->seat, NULL); +} + +static void +meta_wayland_compositor_create_surface (struct wl_client *wayland_client, + struct wl_resource *wayland_compositor_resource, + guint32 id) +{ + MetaWaylandCompositor *compositor = + wl_resource_get_user_data (wayland_compositor_resource); + MetaWaylandSurface *surface; + + surface = meta_wayland_surface_create (compositor, + wayland_client, id, + MIN (META_WL_SURFACE_VERSION, + wl_resource_get_version (wayland_compositor_resource))); + + compositor->surfaces = g_list_prepend (compositor->surfaces, surface); +} + +static void +meta_wayland_region_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +meta_wayland_region_add (struct wl_client *client, + struct wl_resource *resource, + gint32 x, + gint32 y, + gint32 width, + gint32 height) +{ + MetaWaylandRegion *region = wl_resource_get_user_data (resource); + cairo_rectangle_int_t rectangle = { x, y, width, height }; + + cairo_region_union_rectangle (region->region, &rectangle); +} + +static void +meta_wayland_region_subtract (struct wl_client *client, + struct wl_resource *resource, + gint32 x, + gint32 y, + gint32 width, + gint32 height) +{ + MetaWaylandRegion *region = wl_resource_get_user_data (resource); + cairo_rectangle_int_t rectangle = { x, y, width, height }; + + cairo_region_subtract_rectangle (region->region, &rectangle); +} + +const struct wl_region_interface meta_wayland_region_interface = { + meta_wayland_region_destroy, + meta_wayland_region_add, + meta_wayland_region_subtract +}; + +static void +meta_wayland_region_resource_destroy_cb (struct wl_resource *resource) +{ + MetaWaylandRegion *region = wl_resource_get_user_data (resource); + + cairo_region_destroy (region->region); + g_slice_free (MetaWaylandRegion, region); +} + +static void +meta_wayland_compositor_create_region (struct wl_client *wayland_client, + struct wl_resource *compositor_resource, + uint32_t id) +{ + MetaWaylandRegion *region = g_slice_new0 (MetaWaylandRegion); + + region->resource = wl_resource_create (wayland_client, + &wl_region_interface, + MIN (META_WL_REGION_VERSION, + wl_resource_get_version (compositor_resource)), + id); + wl_resource_set_implementation (region->resource, + &meta_wayland_region_interface, region, + meta_wayland_region_resource_destroy_cb); + + region->region = cairo_region_create (); +} + +typedef struct { + MetaOutput *output; + struct wl_global *global; + int x, y; + enum wl_output_transform transform; + + GList *resources; +} MetaWaylandOutput; + +static void +output_resource_destroy (struct wl_resource *res) +{ + MetaWaylandOutput *wayland_output; + + wayland_output = wl_resource_get_user_data (res); + wayland_output->resources = g_list_remove (wayland_output->resources, res); +} + +static void +bind_output (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + MetaWaylandOutput *wayland_output = data; + MetaOutput *output = wayland_output->output; + struct wl_resource *resource; + guint mode_flags; + + resource = wl_resource_create (client, &wl_output_interface, + MIN (META_WL_OUTPUT_VERSION, version), id); + wayland_output->resources = g_list_prepend (wayland_output->resources, resource); + + wl_resource_set_user_data (resource, wayland_output); + wl_resource_set_destructor (resource, output_resource_destroy); + + meta_verbose ("Binding output %p/%s (%u, %u, %u, %u) x %f\n", + output, output->name, + output->crtc->rect.x, output->crtc->rect.y, + output->crtc->rect.width, output->crtc->rect.height, + output->crtc->current_mode->refresh_rate); + + wl_resource_post_event (resource, + WL_OUTPUT_GEOMETRY, + (int)output->crtc->rect.x, + (int)output->crtc->rect.y, + output->width_mm, + output->height_mm, + /* Cogl values reflect XRandR values, + and so does wayland */ + output->subpixel_order, + output->vendor, + output->product, + output->crtc->transform); + + g_assert (output->crtc->current_mode != NULL); + + mode_flags = WL_OUTPUT_MODE_CURRENT; + if (output->crtc->current_mode == output->preferred_mode) + mode_flags |= WL_OUTPUT_MODE_PREFERRED; + + wl_resource_post_event (resource, + WL_OUTPUT_MODE, + mode_flags, + (int)output->crtc->current_mode->width, + (int)output->crtc->current_mode->height, + (int)output->crtc->current_mode->refresh_rate); + + if (version >= META_WL_OUTPUT_HAS_DONE) + wl_resource_post_event (resource, + WL_OUTPUT_DONE); +} + +static void +wayland_output_destroy_notify (gpointer data) +{ + MetaWaylandOutput *wayland_output = data; + GList *resources; + + /* Make sure the destructors don't mess with the list */ + resources = wayland_output->resources; + wayland_output->resources = NULL; + + wl_global_destroy (wayland_output->global); + g_list_free (resources); + + g_slice_free (MetaWaylandOutput, wayland_output); +} + +static void +wayland_output_update_for_output (MetaWaylandOutput *wayland_output, + MetaOutput *output) +{ + GList *iter; + guint mode_flags; + + g_assert (output->crtc->current_mode != NULL); + + mode_flags = WL_OUTPUT_MODE_CURRENT; + if (output->crtc->current_mode == output->preferred_mode) + mode_flags |= WL_OUTPUT_MODE_PREFERRED; + + for (iter = wayland_output->resources; iter; iter = iter->next) + { + struct wl_resource *resource = iter->data; + + if (wayland_output->x != output->crtc->rect.x || + wayland_output->y != output->crtc->rect.y || + wayland_output->transform != output->crtc->transform) + { + wl_resource_post_event (resource, + WL_OUTPUT_GEOMETRY, + (int)output->crtc->rect.x, + (int)output->crtc->rect.y, + output->width_mm, + output->height_mm, + output->subpixel_order, + output->vendor, + output->product, + output->crtc->transform); + } + + wl_resource_post_event (resource, + WL_OUTPUT_MODE, + mode_flags, + (int)output->crtc->current_mode->width, + (int)output->crtc->current_mode->height, + (int)output->crtc->current_mode->refresh_rate); + } + + /* It's very important that we change the output pointer here, as + the old structure is about to be freed by MetaMonitorManager */ + wayland_output->output = output; + wayland_output->x = output->crtc->rect.x; + wayland_output->y = output->crtc->rect.y; + wayland_output->transform = output->crtc->transform; +} + +static GHashTable * +meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor, + MetaMonitorManager *monitors) +{ + MetaOutput *outputs; + unsigned int i, n_outputs; + GHashTable *new_table; + + outputs = meta_monitor_manager_get_outputs (monitors, &n_outputs); + new_table = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify); + + for (i = 0; i < n_outputs; i++) + { + MetaOutput *output = &outputs[i]; + MetaWaylandOutput *wayland_output; + + /* wayland does not expose disabled outputs */ + if (output->crtc == NULL) + { + g_hash_table_remove (compositor->outputs, GSIZE_TO_POINTER (output->output_id)); + continue; + } + + wayland_output = g_hash_table_lookup (compositor->outputs, GSIZE_TO_POINTER (output->output_id)); + + if (wayland_output) + { + g_hash_table_steal (compositor->outputs, GSIZE_TO_POINTER (output->output_id)); + } + else + { + wayland_output = g_slice_new0 (MetaWaylandOutput); + wayland_output->global = wl_global_create (compositor->wayland_display, + &wl_output_interface, + META_WL_OUTPUT_VERSION, + wayland_output, bind_output); + } + + wayland_output_update_for_output (wayland_output, output); + g_hash_table_insert (new_table, GSIZE_TO_POINTER (output->output_id), wayland_output); + } + + g_hash_table_destroy (compositor->outputs); + return new_table; +} + +const static struct wl_compositor_interface meta_wayland_compositor_interface = { + meta_wayland_compositor_create_surface, + meta_wayland_compositor_create_region +}; + +void +meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor) +{ + while (!wl_list_empty (&compositor->frame_callbacks)) + { + MetaWaylandFrameCallback *callback = + wl_container_of (compositor->frame_callbacks.next, callback, link); + + wl_callback_send_done (callback->resource, get_time ()); + wl_resource_destroy (callback->resource); + } +} + +static void +compositor_bind (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + MetaWaylandCompositor *compositor = data; + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_compositor_interface, + MIN (META_WL_COMPOSITOR_VERSION, version), id); + wl_resource_set_implementation (resource, &meta_wayland_compositor_interface, compositor, NULL); +} + +static void +stage_destroy_cb (void) +{ + meta_quit (META_EXIT_SUCCESS); +} + +/** + * meta_wayland_compositor_update: + * @compositor: the #MetaWaylandCompositor instance + * @event: the #ClutterEvent used to update @seat's state + * + * This is used to update display server state like updating cursor + * position and keeping track of buttons and keys pressed. It must be + * called for all input events coming from the underlying devices. + */ +void +meta_wayland_compositor_update (MetaWaylandCompositor *compositor, + const ClutterEvent *event) +{ + meta_wayland_seat_update (compositor->seat, event); +} + +/** + * meta_wayland_compositor_handle_event: + * @compositor: the #MetaWaylandCompositor instance + * @event: the #ClutterEvent to be sent + * + * This method sends events to the focused wayland client, if any. + * + * Return value: whether @event was sent to a wayland client. + */ +gboolean +meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor, + const ClutterEvent *event) +{ + return meta_wayland_seat_handle_event (compositor->seat, event); +} + +static void +on_monitors_changed (MetaMonitorManager *monitors, + MetaWaylandCompositor *compositor) +{ + compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors); +} + +static void +set_gnome_env (const char *name, + const char *value) +{ + GDBusConnection *session_bus; + GError *error = NULL; + + setenv (name, value, TRUE); + + session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + g_assert (session_bus); + + g_dbus_connection_call_sync (session_bus, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.gnome.SessionManager", + "Setenv", + g_variant_new ("(ss)", name, value), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (error) + { + if (g_strcmp0 (g_dbus_error_get_remote_error (error), "org.gnome.SessionManager.NotInInitialization") != 0) + meta_warning ("Failed to set environment variable %s for gnome-session: %s\n", name, error->message); + + g_error_free (error); + } +} + +static void +meta_wayland_log_func (const char *fmt, + va_list arg) +{ + char *str = g_strdup_vprintf (fmt, arg); + g_warning ("WL: %s", str); + g_free (str); +} + +void +meta_wayland_init (void) +{ + MetaWaylandCompositor *compositor = &_meta_wayland_compositor; + MetaMonitorManager *monitors; + + memset (compositor, 0, sizeof (MetaWaylandCompositor)); + + compositor->wayland_display = wl_display_create (); + if (compositor->wayland_display == NULL) + g_error ("failed to create wayland display"); + + wl_display_init_shm (compositor->wayland_display); + wl_log_set_handler_server(meta_wayland_log_func); + + wl_list_init (&compositor->frame_callbacks); + + if (!wl_global_create (compositor->wayland_display, + &wl_compositor_interface, + META_WL_COMPOSITOR_VERSION, + compositor, compositor_bind)) + g_error ("Failed to register wayland compositor object"); + + compositor->wayland_loop = + wl_display_get_event_loop (compositor->wayland_display); + compositor->wayland_event_source = + wayland_event_source_new (compositor->wayland_display); + + /* XXX: Here we are setting the wayland event source to have a + * slightly lower priority than the X event source, because we are + * much more likely to get confused being told about surface changes + * relating to X clients when we don't know what's happened to them + * according to the X protocol. + * + * At some point we could perhaps try and get the X protocol proxied + * over the wayland protocol so that we don't have to worry about + * synchronizing the two command streams. */ + g_source_set_priority (compositor->wayland_event_source, + GDK_PRIORITY_EVENTS + 1); + g_source_attach (compositor->wayland_event_source, NULL); + + clutter_wayland_set_compositor_display (compositor->wayland_display); + + meta_clutter_init (); + + meta_monitor_manager_initialize (); + monitors = meta_monitor_manager_get (); + g_signal_connect (monitors, "monitors-changed", + G_CALLBACK (on_monitors_changed), compositor); + + compositor->outputs = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify); + compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors); + + compositor->stage = meta_wayland_stage_new (); + g_signal_connect (compositor->stage, "destroy", + G_CALLBACK (stage_destroy_cb), NULL); + + meta_wayland_data_device_manager_init (compositor->wayland_display); + + compositor->seat = meta_wayland_seat_new (compositor->wayland_display); + + meta_wayland_init_shell (compositor); + + clutter_actor_show (compositor->stage); + + /* FIXME: find the first free name instead */ + compositor->display_name = g_strdup ("wayland-0"); + if (wl_display_add_socket (compositor->wayland_display, compositor->display_name)) + g_error ("Failed to create socket"); + + /* XXX: It's important that we only try and start xwayland after we + * have initialized EGL because EGL implements the "wl_drm" + * interface which xwayland requires to determine what drm device + * name it should use. + * + * By waiting until we've shown the stage above we ensure that the + * underlying GL resources for the surface have also been allocated + * and so EGL must be initialized by this point. + */ + + if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display)) + g_error ("Failed to start X Wayland"); + + set_gnome_env ("DISPLAY", compositor->xwayland_manager.display_name); + set_gnome_env ("WAYLAND_DISPLAY", compositor->display_name); +} + +void +meta_wayland_finalize (void) +{ + MetaWaylandCompositor *compositor; + + compositor = meta_wayland_compositor_get_default (); + + meta_xwayland_stop (&compositor->xwayland_manager); +} diff --git a/src/wayland/meta-wayland.h b/src/wayland/meta-wayland.h new file mode 100644 index 0000000..4f12660 --- /dev/null +++ b/src/wayland/meta-wayland.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#ifndef META_WAYLAND_H +#define META_WAYLAND_H + +#include "meta-wayland-types.h" + +void meta_wayland_init (void); +void meta_wayland_finalize (void); + +/* We maintain a singleton MetaWaylandCompositor which can be got at via this + * API after meta_wayland_init() has been called. */ +MetaWaylandCompositor *meta_wayland_compositor_get_default (void); + +void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor); + +void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor, + MetaWindow *window); +gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor, + const ClutterEvent *event); + +void meta_wayland_compositor_update (MetaWaylandCompositor *compositor, + const ClutterEvent *event); +void meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor); + +#endif + diff --git a/src/wayland/meta-xwayland-private.h b/src/wayland/meta-xwayland-private.h new file mode 100644 index 0000000..83b2986 --- /dev/null +++ b/src/wayland/meta-xwayland-private.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_XWAYLAND_PRIVATE_H +#define META_XWAYLAND_PRIVATE_H + +#include "meta-wayland-private.h" + +#include <glib.h> + +gboolean +meta_xwayland_start (MetaXWaylandManager *manager, + struct wl_display *display); + +void +meta_xwayland_complete_init (void); + +void +meta_xwayland_stop (MetaXWaylandManager *manager); + +#endif /* META_XWAYLAND_PRIVATE_H */ diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c new file mode 100644 index 0000000..a4ec03f --- /dev/null +++ b/src/wayland/meta-xwayland.c @@ -0,0 +1,477 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * X Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "meta-xwayland.h" +#include "meta-xwayland-private.h" + +#include "meta-wayland-surface-private.h" + +#include <glib.h> +#include <glib-unix.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/wait.h> +#include <stdlib.h> + +static void +associate_window_with_surface (MetaWindow *window, + MetaWaylandSurface *surface) +{ + MetaDisplay *display = window->display; + + /* If the window has an existing surface, like if we're + * undecorating or decorating the window, then we need + * to detach the window from its old surface. + */ + if (window->surface) + window->surface->window = NULL; + + meta_wayland_surface_set_window (surface, window); + window->surface = surface; + + meta_compositor_window_surface_changed (display->compositor, window); + + /* Since the association comes in the form of a ClientMessage, + * we have no way to know when the surface was set up. Since + * commit just breaks if we don't have a window associated with + * it, we need to do a commit *again* here. */ + meta_wayland_surface_commit (surface); + + /* Now that we have a surface check if it should have focus. */ + meta_display_sync_wayland_input_focus (display); +} + +static gboolean +associate_window_with_surface_id (MetaXWaylandManager *manager, + MetaWindow *window, + guint32 surface_id) +{ + struct wl_resource *resource; + + resource = wl_client_get_object (manager->client, surface_id); + if (resource) + { + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + associate_window_with_surface (window, surface); + return TRUE; + } + else + return FALSE; +} + +typedef struct { + MetaXWaylandManager *manager; + MetaWindow *window; + guint32 surface_id; +} AssociateWindowWithSurfaceOp; + +static gboolean +associate_window_with_surface_idle (gpointer user_data) +{ + AssociateWindowWithSurfaceOp *op = user_data; + if (!associate_window_with_surface_id (op->manager, op->window, op->surface_id)) + { + /* Not here? Oh well... nothing we can do */ + g_warning ("Unknown surface ID %d (from window %s)", op->surface_id, op->window->desc); + } + g_free (op); + + return G_SOURCE_REMOVE; +} + +void +meta_xwayland_handle_wl_surface_id (MetaWindow *window, + guint32 surface_id) +{ + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + MetaXWaylandManager *manager = &compositor->xwayland_manager; + + if (!associate_window_with_surface_id (manager, window, surface_id)) + { + /* No surface ID yet... it should arrive after the next + * iteration through the loop, so queue an idle and see + * what happens. + */ + AssociateWindowWithSurfaceOp *op = g_new0 (AssociateWindowWithSurfaceOp, 1); + op->manager = manager; + op->window = window; + op->surface_id = surface_id; + g_idle_add (associate_window_with_surface_idle, op); + } +} + +static char * +create_lockfile (int display, int *display_out) +{ + char *filename; + int size; + char pid[11]; + int fd; + + do + { + char *end; + pid_t other; + + filename = g_strdup_printf ("/tmp/.X%d-lock", display); + fd = open (filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444); + + if (fd < 0 && errno == EEXIST) + { + fd = open (filename, O_CLOEXEC, O_RDONLY); + if (fd < 0 || read (fd, pid, 11) != 11) + { + const char *msg = strerror (errno); + g_warning ("can't read lock file %s: %s", filename, msg); + g_free (filename); + + /* ignore error and try the next display number */ + display++; + continue; + } + close (fd); + + other = strtol (pid, &end, 0); + if (end != pid + 10) + { + g_warning ("can't parse lock file %s", filename); + g_free (filename); + + /* ignore error and try the next display number */ + display++; + continue; + } + + if (kill (other, 0) < 0 && errno == ESRCH) + { + if (unlink (filename) < 0) + { + const char *msg = strerror (errno); + g_warning ("failed to unlink stale lock file: %s", msg); + display++; + } + g_free (filename); + continue; + } + + g_free (filename); + display++; + continue; + } + else if (fd < 0) + { + const char *msg = strerror (errno); + g_warning ("failed to create lock file %s: %s", filename , msg); + g_free (filename); + return NULL; + } + + break; + } + while (1); + + /* Subtle detail: we use the pid of the wayland compositor, not the xserver + * in the lock file. */ + size = snprintf (pid, 11, "%10d\n", getpid ()); + if (size != 11 || write (fd, pid, 11) != 11) + { + unlink (filename); + close (fd); + g_warning ("failed to write pid to lock file %s", filename); + g_free (filename); + return NULL; + } + + close (fd); + + *display_out = display; + return filename; +} + +static int +bind_to_abstract_socket (int display) +{ + struct sockaddr_un addr; + socklen_t size, name_size; + int fd; + + fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) + return -1; + + addr.sun_family = AF_LOCAL; + name_size = snprintf (addr.sun_path, sizeof addr.sun_path, + "%c/tmp/.X11-unix/X%d", 0, display); + size = offsetof (struct sockaddr_un, sun_path) + name_size; + if (bind (fd, (struct sockaddr *) &addr, size) < 0) + { + g_warning ("failed to bind to @%s: %m", addr.sun_path + 1); + close (fd); + return -1; + } + + if (listen (fd, 1) < 0) + { + close (fd); + return -1; + } + + return fd; +} + +static int +bind_to_unix_socket (int display) +{ + struct sockaddr_un addr; + socklen_t size, name_size; + int fd; + + fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) + return -1; + + addr.sun_family = AF_LOCAL; + name_size = snprintf (addr.sun_path, sizeof addr.sun_path, + "/tmp/.X11-unix/X%d", display) + 1; + size = offsetof (struct sockaddr_un, sun_path) + name_size; + unlink (addr.sun_path); + if (bind (fd, (struct sockaddr *) &addr, size) < 0) + { + g_warning ("failed to bind to %s: %m\n", addr.sun_path); + close (fd); + return -1; + } + + if (listen (fd, 1) < 0) + { + unlink (addr.sun_path); + close (fd); + return -1; + } + + return fd; +} + +static void +xserver_died (GPid pid, + gint status, + gpointer user_data) +{ + if (!WIFEXITED (status)) + g_error ("X Wayland crashed; aborting"); + else + { + /* For now we simply abort if we see the server exit. + * + * In the future X will only be loaded lazily for legacy X support + * but for now it's a hard requirement. */ + g_error ("Spurious exit of X Wayland server"); + } +} + +static int +x_io_error (Display *display) +{ + g_error ("Connection to xwayland lost"); + + return 0; +} + +static gboolean +choose_xdisplay (MetaXWaylandManager *manager) +{ + int display = 0; + char *lockfile = NULL; + + do + { + lockfile = create_lockfile (display, &display); + if (!lockfile) + { + g_warning ("Failed to create an X lock file"); + return FALSE; + } + + manager->abstract_fd = bind_to_abstract_socket (display); + if (manager->abstract_fd < 0) + { + unlink (lockfile); + + if (errno == EADDRINUSE) + { + display++; + continue; + } + else + return FALSE; + } + + manager->unix_fd = bind_to_unix_socket (display); + if (manager->abstract_fd < 0) + { + unlink (lockfile); + close (manager->abstract_fd); + return FALSE; + } + + break; + } + while (1); + + manager->display_index = display; + manager->display_name = g_strdup_printf (":%d", manager->display_index); + manager->lockfile = lockfile; + + return TRUE; +} + +static void +xserver_finished_init (MetaXWaylandManager *manager) +{ + /* At this point xwayland is all setup to start accepting + * connections so we can quit the transient initialization mainloop + * and unblock meta_wayland_init() to continue initializing mutter. + * */ + g_main_loop_quit (manager->init_loop); + g_clear_pointer (&manager->init_loop, g_main_loop_unref); +} + +static gboolean +got_sigusr1 (gpointer user_data) +{ + MetaXWaylandManager *manager = user_data; + + xserver_finished_init (manager); + + return G_SOURCE_REMOVE; +} + +gboolean +meta_xwayland_start (MetaXWaylandManager *manager, + struct wl_display *wl_display) +{ + int sp[2]; + int fd; + + if (!choose_xdisplay (manager)) + return FALSE; + + /* We want xwayland to be a wayland client so we make a socketpair to setup a + * wayland protocol connection. */ + if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sp) < 0) + { + g_warning ("socketpair failed\n"); + unlink (manager->lockfile); + return 1; + } + + manager->pid = fork (); + if (manager->pid == 0) + { + char socket_fd[8], unix_fd[8], abstract_fd[8]; + + /* We passed SOCK_CLOEXEC, so dup the FD so it isn't + * closed on exec.. */ + fd = dup (sp[1]); + snprintf (socket_fd, sizeof (socket_fd), "%d", fd); + setenv ("WAYLAND_SOCKET", socket_fd, TRUE); + + fd = dup (manager->abstract_fd); + snprintf (abstract_fd, sizeof (abstract_fd), "%d", fd); + + fd = dup (manager->unix_fd); + snprintf (unix_fd, sizeof (unix_fd), "%d", fd); + + /* xwayland, please. */ + if (getenv ("XWAYLAND_STFU")) + { + int dev_null; + dev_null = open ("/dev/null", O_WRONLY); + + dup2 (dev_null, STDOUT_FILENO); + dup2 (dev_null, STDERR_FILENO); + } + + /* We have to ignore SIGUSR1 in the child to make sure + * that the server will send it to mutter-wayland. */ + signal(SIGUSR1, SIG_IGN); + + if (execl (XWAYLAND_PATH, XWAYLAND_PATH, + manager->display_name, + "-rootless", + "-noreset", + "-listen", abstract_fd, + "-listen", unix_fd, + NULL) < 0) + { + g_error ("Failed to spawn XWayland: %m"); + } + } + else if (manager->pid == -1) + { + g_error ("Failed to fork: %m"); + } + + g_child_watch_add (manager->pid, xserver_died, NULL); + g_unix_signal_add (SIGUSR1, got_sigusr1, manager); + manager->client = wl_client_create (wl_display, sp[0]); + + /* We need to run a mainloop until we know xwayland has a binding + * for our xserver interface at which point we can assume it's + * ready to start accepting connections. */ + manager->init_loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (manager->init_loop); + + return TRUE; +} + +/* To be called right after connecting */ +void +meta_xwayland_complete_init (void) +{ + /* We install an X IO error handler in addition to the child watch, + because after Xlib connects our child watch may not be called soon + enough, and therefore we won't crash when X exits (and most important + we won't reset the tty). + */ + XSetIOErrorHandler (x_io_error); +} + +void +meta_xwayland_stop (MetaXWaylandManager *manager) +{ + char path[256]; + + snprintf (path, sizeof path, "/tmp/.X%d-lock", manager->display_index); + unlink (path); + snprintf (path, sizeof path, "/tmp/.X11-unix/X%d", manager->display_index); + unlink (path); + + unlink (manager->lockfile); +} diff --git a/src/wayland/meta-xwayland.h b/src/wayland/meta-xwayland.h new file mode 100644 index 0000000..5308f29 --- /dev/null +++ b/src/wayland/meta-xwayland.h @@ -0,0 +1,35 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#ifndef META_XWAYLAND_H +#define META_XWAYLAND_H + +#include <glib.h> +#include <meta/types.h> + +void +meta_xwayland_handle_wl_surface_id (MetaWindow *window, + guint32 surface_id); + +#endif /* META_XWAYLAND_H */ diff --git a/src/wayland/protocol/gtk-shell.xml b/src/wayland/protocol/gtk-shell.xml new file mode 100644 index 0000000..e2cc4f4 --- /dev/null +++ b/src/wayland/protocol/gtk-shell.xml @@ -0,0 +1,30 @@ +<protocol name="gtk"> + + <interface name="gtk_shell" version="1"> + <enum name="capability"> + <entry name="global_app_menu" value="1"/> + <entry name="global_menu_bar" value="2"/> + </enum> + + <event name="capabilities"> + <arg name="capabilities" type="uint"/> + </event> + + <request name="get_gtk_surface"> + <arg name="gtk_surface" type="new_id" interface="gtk_surface"/> + <arg name="surface" type="object" interface="wl_surface"/> + </request> + </interface> + + <interface name="gtk_surface" version="1"> + <request name="set_dbus_properties"> + <arg name="application_id" type="string" allow-null="true"/> + <arg name="app_menu_path" type="string" allow-null="true"/> + <arg name="menubar_path" type="string" allow-null="true"/> + <arg name="window_object_path" type="string" allow-null="true"/> + <arg name="application_object_path" type="string" allow-null="true"/> + <arg name="unique_bus_name" type="string" allow-null="true"/> + </request> + </interface> + +</protocol> diff --git a/src/wayland/protocol/xdg-shell.xml b/src/wayland/protocol/xdg-shell.xml new file mode 100644 index 0000000..a2913c4 --- /dev/null +++ b/src/wayland/protocol/xdg-shell.xml @@ -0,0 +1,444 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="xdg_shell"> + + <copyright> + Copyright © 2008-2013 Kristian Høgsberg + Copyright © 2013 Rafael Antognolli + Copyright © 2013 Jasper St. Pierre + Copyright © 2010-2013 Intel Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + </copyright> + + <interface name="xdg_shell" version="1"> + <description summary="create desktop-style surfaces"> + This interface is implemented by servers that provide + desktop-style user interfaces. + + It allows clients to associate a xdg_surface with + a basic surface. + </description> + + <enum name="version"> + <description summary="latest protocol version"> + The 'current' member of this enum gives the version of the + protocol. Implementations can compare this to the version + they implement using static_assert to ensure the protocol and + implementation versions match. + </description> + <entry name="current" value="3" summary="Always the latest version"/> + </enum> + + + <request name="use_unstable_version"> + <description summary="enable use of this unstable version"> + Negotiate the unstable version of the interface. This + mechanism is in place to ensure client and server agree on the + unstable versions of the protocol that they speak or exit + cleanly if they don't agree. This request will go away once + the xdg-shell protocol is stable. + </description> + <arg name="version" type="int"/> + </request> + + <request name="get_xdg_surface"> + <description summary="create a shell surface from a surface"> + Create a shell surface for an existing surface. + + Only one shell or popup surface can be associated with a given + surface. + </description> + <arg name="id" type="new_id" interface="xdg_surface"/> + <arg name="surface" type="object" interface="wl_surface"/> + </request> + + <request name="get_xdg_popup"> + <description summary="create a shell surface from a surface"> + Create a popup surface for an existing surface. + + Only one shell or popup surface can be associated with a given + surface. + </description> + <arg name="id" type="new_id" interface="xdg_popup"/> + <arg name="surface" type="object" interface="wl_surface"/> + <arg name="parent" type="object" interface="wl_surface"/> + <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> + <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> + <arg name="x" type="int"/> + <arg name="y" type="int"/> + <arg name="flags" type="uint"/> + </request> + + <event name="ping"> + <description summary="check if the client is alive"> + The ping event asks the client if it's still alive. Pass the + serial specified in the event back to the compositor by sending + a "pong" request back with the specified serial. + + Compositors can use this to determine if the client is still + alive. It's unspecified what will happen if the client doesn't + respond to the ping request, or in what timeframe. Clients should + try to respond in a reasonable amount of time. + </description> + <arg name="serial" type="uint" summary="pass this to the callback"/> + </event> + + <request name="pong"> + <description summary="respond to a ping event"> + A client must respond to a ping event with a pong request or + the client may be deemed unresponsive. + </description> + <arg name="serial" type="uint" summary="serial of the ping event"/> + </request> + </interface> + + <interface name="xdg_surface" version="1"> + + <description summary="desktop-style metadata interface"> + An interface that may be implemented by a wl_surface, for + implementations that provide a desktop-style user interface. + + It provides requests to treat surfaces like windows, allowing to set + properties like maximized, fullscreen, minimized, and to move and resize + them, and associate metadata like title and app id. + + On the server side the object is automatically destroyed when + the related wl_surface is destroyed. On client side, + xdg_surface.destroy() must be called before destroying + the wl_surface object. + </description> + + <request name="destroy" type="destructor"> + <description summary="remove xdg_surface interface"> + The xdg_surface interface is removed from the wl_surface object + that was turned into a xdg_surface with + xdg_shell.get_xdg_surface request. The xdg_surface properties, + like maximized and fullscreen, are lost. The wl_surface loses + its role as a xdg_surface. The wl_surface is unmapped. + </description> + </request> + + <request name="set_transient_for"> + <description summary="surface is a child of another surface"> + Setting a surface as transient of another means that it is child + of another surface. + + Child surfaces are stacked above their parents, and will be + unmapped if the parent is unmapped too. They should not appear + on task bars and alt+tab. + </description> + <arg name="parent" type="object" interface="wl_surface" allow-null="true"/> + </request> + + <request name="set_margin"> + <description summary="set the visible frame boundaries"> + This tells the compositor what the visible size of the window + should be, so it can use it to determine what borders to use for + constrainment and alignment. + + CSD often has invisible areas for decoration purposes, like drop + shadows. These "shadow" drawings need to be subtracted out of the + normal boundaries of the window when computing where to place + windows (e.g. to set this window so it's centered on top of another, + or to put it to the left or right of the screen.) + + This value should change as little as possible at runtime, to + prevent flicker. + + This value is also ignored when the window is maximized or + fullscreen, and assumed to be 0. + + If never called, this value is assumed to be 0. + </description> + <arg name="left_margin" type="int"/> + <arg name="right_margin" type="int"/> + <arg name="top_margin" type="int"/> + <arg name="bottom_margin" type="int"/> + </request> + + <request name="set_title"> + <description summary="set surface title"> + Set a short title for the surface. + + This string may be used to identify the surface in a task bar, + window list, or other user interface elements provided by the + compositor. + + The string must be encoded in UTF-8. + </description> + <arg name="title" type="string"/> + </request> + + <request name="set_app_id"> + <description summary="set surface class"> + Set an id for the surface. + + The app id identifies the general class of applications to which + the surface belongs. + + It should be the ID that appears in the new desktop entry + specification, the interface name. + </description> + <arg name="app_id" type="string"/> + </request> + + <request name="move"> + <description summary="start an interactive move"> + Start a pointer-driven move of the surface. + + This request must be used in response to a button press event. + The server may ignore move requests depending on the state of + the surface (e.g. fullscreen or maximized). + </description> + <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> + <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> + </request> + + <enum name="resize_edge"> + <description summary="edge values for resizing"> + These values are used to indicate which edge of a surface + is being dragged in a resize operation. The server may + use this information to adapt its behavior, e.g. choose + an appropriate cursor image. + </description> + <entry name="none" value="0"/> + <entry name="top" value="1"/> + <entry name="bottom" value="2"/> + <entry name="left" value="4"/> + <entry name="top_left" value="5"/> + <entry name="bottom_left" value="6"/> + <entry name="right" value="8"/> + <entry name="top_right" value="9"/> + <entry name="bottom_right" value="10"/> + </enum> + + <request name="resize"> + <description summary="start an interactive resize"> + Start a pointer-driven resizing of the surface. + + This request must be used in response to a button press event. + The server may ignore resize requests depending on the state of + the surface (e.g. fullscreen or maximized). + </description> + <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> + <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> + <arg name="edges" type="uint" summary="which edge or corner is being dragged"/> + </request> + + <event name="configure"> + <description summary="suggest resize"> + The configure event asks the client to resize its surface. + + The size is a hint, in the sense that the client is free to + ignore it if it doesn't resize, pick a smaller size (to + satisfy aspect ratio or resize in steps of NxM pixels). + + The client is free to dismiss all but the last configure + event it received. + + The width and height arguments specify the size of the window + in surface local coordinates. + </description> + + <arg name="width" type="int"/> + <arg name="height" type="int"/> + </event> + + <request name="set_output"> + <description summary="set the default output used by this surface"> + Set the default output used by this surface when it is first mapped. + + If this value is NULL (default), it's up to the compositor to choose + which display will be used to map this surface. + + When fullscreen or maximized state are set on this surface, and it + wasn't mapped yet, the output set with this method will be used. + Otherwise, the output where the surface is currently mapped will be + used. + </description> + <arg name="output" type="object" interface="wl_output" allow-null="true"/> + </request> + + <enum name="state"> + <description summary="types of state on the surface"> + The different state values used on the surface. This is designed for + state values like maximized, fullscreen. It is paired with the + request_change_state event to ensure that both the client and the + compositor setting the state can be synchronized. + + States set in this way are double-buffered. They will get applied on + the next commit. + + Desktop environments may extend this enum by taking up a range of + values and documenting the range they chose in this description. + They are not required to document the values for the range that they + chose. Ideally, any good extensions from a desktop environment should + make its way into standardization into this enum. + + The current reserved ranges are: + + 0x0000 - 0x0FFF: xdg-shell core values, documented below. + 0x1000 - 0x1FFF: GNOME + </description> + <entry name="maximized" value="1" summary="the surface is maximized"> + A non-zero value indicates the surface is maximized. Otherwise, + the surface is unmaximized. + </entry> + <entry name="fullscreen" value="2" summary="the surface is fullscreen"> + A non-zero value indicates the surface is fullscreen. Otherwise, + the surface is not fullscreen. + </entry> + </enum> + + <request name="request_change_state"> + <description summary="client requests to change a surface's state"> + This asks the compositor to change the state. If the compositor wants + to change the state, it will send a change_state event with the same + state_type, value, and serial, and the event flow continues as if it + it was initiated by the compositor. + + If the compositor does not want to change the state, it will send a + change_state to the client with the old value of the state. + </description> + <arg name="state_type" type="uint" summary="the state to set"/> + <arg name="value" type="uint" summary="the value to change the state to"/> + <arg name="serial" type="uint" summary="an event serial"> + This serial is so the client can know which change_state event corresponds + to which request_change_state request it sent out. + </arg> + </request> + + <event name="change_state"> + <description summary="compositor wants to change a surface's state"> + This event tells the client to change a surface's state. The client + should respond with an ack_change_state request to the compositor to + guarantee that the compositor knows that the client has seen it. + </description> + + <arg name="state_type" type="uint" summary="the state to set"/> + <arg name="value" type="uint" summary="the value to change the state to"/> + <arg name="serial" type="uint" summary="a serial for the compositor's own tracking"/> + </event> + + <request name="ack_change_state"> + <description summary="ack a change_state event"> + When a change_state event is received, a client should then ack it + using the ack_change_state request to ensure that the compositor + knows the client has seen the event. + + By this point, the state is confirmed, and the next attach should + contain the buffer drawn for the new state value. + + The values here need to be the same as the values in the cooresponding + change_state event. + </description> + <arg name="state_type" type="uint" summary="the state to set"/> + <arg name="value" type="uint" summary="the value to change the state to"/> + <arg name="serial" type="uint" summary="a serial to pass to change_state"/> + </request> + + <request name="set_minimized"> + <description summary="minimize the surface"> + Minimize the surface. + </description> + </request> + + <event name="activated"> + <description summary="surface was activated"> + The activated_set event is sent when this surface has been + activated, which means that the surface has user attention. + Window decorations should be updated accordingly. You should + not use this event for anything but the style of decorations + you display, use wl_keyboard.enter and wl_keyboard.leave for + determining keyboard focus. + </description> + </event> + + <event name="deactivated"> + <description summary="surface was deactivated"> + The deactivate event is sent when this surface has been + deactivated, which means that the surface lost user attention. + Window decorations should be updated accordingly. You should + not use this event for anything but the style of decorations + you display, use wl_keyboard.enter and wl_keyboard.leave for + determining keyboard focus. + </description> + </event> + + <event name="delete"> + <description summary="surface wants to be closed"> + The delete event is sent by the compositor when the user + wants the surface to be closed. This should be equivalent to + the user clicking the close button in client-side decorations, + if your application has any... + + This is only a request that the user intends to close your + window. The client may choose to ignore this request, or show + a dialog to ask the user to save their data... + </description> + </event> + </interface> + + <interface name="xdg_popup" version="1"> + <description summary="desktop-style metadata interface"> + An interface that may be implemented by a wl_surface, for + implementations that provide a desktop-style popups/menus. A popup + surface is a transient surface with an added pointer grab. + + An existing implicit grab will be changed to owner-events mode, + and the popup grab will continue after the implicit grab ends + (i.e. releasing the mouse button does not cause the popup to be + unmapped). + + The popup grab continues until the window is destroyed or a mouse + button is pressed in any other clients window. A click in any of + the clients surfaces is reported as normal, however, clicks in + other clients surfaces will be discarded and trigger the callback. + + The x and y arguments specify the locations of the upper left + corner of the surface relative to the upper left corner of the + parent surface, in surface local coordinates. + + xdg_popup surfaces are always transient for another surface. + </description> + + <request name="destroy" type="destructor"> + <description summary="remove xdg_surface interface"> + The xdg_surface interface is removed from the wl_surface object + that was turned into a xdg_surface with + xdg_shell.get_xdg_surface request. The xdg_surface properties, + like maximized and fullscreen, are lost. The wl_surface loses + its role as a xdg_surface. The wl_surface is unmapped. + </description> + </request> + + <event name="popup_done"> + <description summary="popup interaction is done"> + The popup_done event is sent out when a popup grab is broken, + that is, when the users clicks a surface that doesn't belong + to the client owning the popup surface. + </description> + <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> + </event> + + </interface> +</protocol> diff --git a/src/wayland/window-wayland.c b/src/wayland/window-wayland.c new file mode 100644 index 0000000..e52c143 --- /dev/null +++ b/src/wayland/window-wayland.c @@ -0,0 +1,220 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#include "config.h" + +#include "window-wayland.h" + +#include "window-private.h" +#include "boxes-private.h" +#include "stack-tracker.h" +#include "meta-wayland-surface.h" + +struct _MetaWindowWayland +{ + MetaWindow parent; +}; + +struct _MetaWindowWaylandClass +{ + MetaWindowClass parent_class; +}; + +G_DEFINE_TYPE (MetaWindowWayland, meta_window_wayland, META_TYPE_WINDOW) + +static void +meta_window_wayland_manage (MetaWindow *window) +{ + MetaDisplay *display = window->display; + + meta_display_register_wayland_window (display, window); + + { + MetaStackWindow stack_window; + stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND; + stack_window.wayland.meta_window = window; + meta_stack_tracker_record_add (window->screen->stack_tracker, + &stack_window, + 0); + } +} + +static void +meta_window_wayland_unmanage (MetaWindow *window) +{ + { + MetaStackWindow stack_window; + stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND; + stack_window.wayland.meta_window = window; + meta_stack_tracker_record_remove (window->screen->stack_tracker, + &stack_window, + 0); + } + + meta_display_unregister_wayland_window (window->display, window); +} + +static void +meta_window_wayland_ping (MetaWindow *window, + guint32 serial) +{ + meta_wayland_surface_ping (window->surface, serial); +} + +static void +meta_window_wayland_delete (MetaWindow *window, + guint32 timestamp) +{ + meta_wayland_surface_delete (window->surface); +} + +static void +meta_window_wayland_kill (MetaWindow *window) +{ + MetaWaylandSurface *surface = window->surface; + struct wl_resource *resource = surface->resource; + + /* Send the client an unrecoverable error to kill the client. */ + wl_resource_post_error (resource, + WL_DISPLAY_ERROR_NO_MEMORY, + "User requested that we kill you. Sorry. Don't take it too personally."); +} + +static void +meta_window_wayland_focus (MetaWindow *window, + guint32 timestamp) +{ + meta_display_set_input_focus_window (window->display, + window, + FALSE, + timestamp); +} + +static void +meta_window_wayland_move_resize_internal (MetaWindow *window, + int gravity, + MetaRectangle requested_rect, + MetaRectangle constrained_rect, + MetaMoveResizeFlags flags, + MetaMoveResizeResultFlags *result) +{ + g_assert (window->frame == NULL); + + /* For wayland clients, the size is completely determined by the client, + * and while this allows to avoid some trickery with frames and the resulting + * lagging, we also need to insist a bit when the constraints would apply + * a different size than the client decides. + * + * Note that this is not generally a problem for normal toplevel windows (the + * constraints don't see the size hints, or just change the position), but + * it can be for maximized or fullscreen. + */ + + /* First, save where we would like the client to be. This is used by the next + * attach to determine if the client is really moving/resizing or not. + */ + window->expected_rect = constrained_rect; + + if (flags & META_IS_WAYLAND_RESIZE) + { + /* This is a call to wl_surface_commit(), ignore the constrained_rect and + * update the real client size to match the buffer size. + */ + + window->rect.width = requested_rect.width; + window->rect.height = requested_rect.height; + } + + if (constrained_rect.width != window->rect.width || + constrained_rect.height != window->rect.height) + { + /* We need to resize the client. Resizing is in two parts: + * some of the movement happens immediately, and some happens as part + * of the resizing (through dx/dy in wl_surface_attach). + * + * To do so, we need to compute the resize from the point of the view + * of the client, and then adjust the immediate resize to match. + * + * dx/dy are the values we expect from the new attach(), while deltax/ + * deltay reflect the overall movement. + */ + MetaRectangle old_rect; + MetaRectangle client_rect; + int dx, dy; + int deltax, deltay; + + meta_window_get_client_root_coords (window, &old_rect); + + meta_rectangle_resize_with_gravity (&old_rect, + &client_rect, + gravity, + constrained_rect.width, + constrained_rect.height); + + deltax = constrained_rect.x - old_rect.x; + deltay = constrained_rect.y - old_rect.y; + dx = client_rect.x - constrained_rect.x; + dy = client_rect.y - constrained_rect.y; + + if (deltax != dx || deltay != dy) + *result |= META_MOVE_RESIZE_RESULT_MOVED; + + window->rect.x += (deltax - dx); + window->rect.y += (deltay - dy); + + *result |= META_MOVE_RESIZE_RESULT_RESIZED; + meta_wayland_surface_configure_notify (window->surface, + constrained_rect.width, + constrained_rect.height); + } + else + { + /* No resize happening, we can just move the window and live with it. */ + if (window->rect.x != constrained_rect.x || + window->rect.y != constrained_rect.y) + *result |= META_MOVE_RESIZE_RESULT_MOVED; + + window->rect.x = constrained_rect.x; + window->rect.y = constrained_rect.y; + } +} + +static void +meta_window_wayland_init (MetaWindowWayland *window_wayland) +{ +} + +static void +meta_window_wayland_class_init (MetaWindowWaylandClass *klass) +{ + MetaWindowClass *window_class = META_WINDOW_CLASS (klass); + + window_class->manage = meta_window_wayland_manage; + window_class->unmanage = meta_window_wayland_unmanage; + window_class->ping = meta_window_wayland_ping; + window_class->delete = meta_window_wayland_delete; + window_class->kill = meta_window_wayland_kill; + window_class->focus = meta_window_wayland_focus; + window_class->move_resize_internal = meta_window_wayland_move_resize_internal; +} diff --git a/src/wayland/window-wayland.h b/src/wayland/window-wayland.h new file mode 100644 index 0000000..c1c6674 --- /dev/null +++ b/src/wayland/window-wayland.h @@ -0,0 +1,44 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre <jstpierre@mecheye.net> + */ + +#ifndef META_WINDOW_WAYLAND_H +#define META_WINDOW_WAYLAND_H + +#include <meta/window.h> + +G_BEGIN_DECLS + +#define META_TYPE_WINDOW_WAYLAND (meta_window_wayland_get_type()) +#define META_WINDOW_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW_WAYLAND, MetaWindowWayland)) +#define META_WINDOW_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW_WAYLAND, MetaWindowWaylandClass)) +#define META_IS_WINDOW_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW_WAYLAND)) +#define META_IS_WINDOW_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW_WAYLAND)) +#define META_WINDOW_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW_WAYLAND, MetaWindowWaylandClass)) + +GType meta_window_wayland_get_type (void); + +typedef struct _MetaWindowWayland MetaWindowWayland; +typedef struct _MetaWindowWaylandClass MetaWindowWaylandClass; + +#endif diff --git a/src/core/async-getprop.c b/src/x11/async-getprop.c index 31b0edc..31b0edc 100644 --- a/src/core/async-getprop.c +++ b/src/x11/async-getprop.c diff --git a/src/core/async-getprop.h b/src/x11/async-getprop.h index c857e93..c857e93 100644 --- a/src/core/async-getprop.h +++ b/src/x11/async-getprop.h diff --git a/src/core/group-private.h b/src/x11/group-private.h index 72e6cd2..72e6cd2 100644 --- a/src/core/group-private.h +++ b/src/x11/group-private.h diff --git a/src/core/group-props.c b/src/x11/group-props.c index 521ffbd..521ffbd 100644 --- a/src/core/group-props.c +++ b/src/x11/group-props.c diff --git a/src/core/group-props.h b/src/x11/group-props.h index 1fb49ea..1fb49ea 100644 --- a/src/core/group-props.h +++ b/src/x11/group-props.h diff --git a/src/core/group.c b/src/x11/group.c index 8965735..8965735 100644 --- a/src/core/group.c +++ b/src/x11/group.c diff --git a/src/core/iconcache.c b/src/x11/iconcache.c index 30018d2..ac09190 100644 --- a/src/core/iconcache.c +++ b/src/x11/iconcache.c @@ -230,7 +230,7 @@ read_rgb_icon (MetaDisplay *display, int mini_w, mini_h; gulong *data_as_long; - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); type = None; data = NULL; result = XGetWindowProperty (display->xdisplay, @@ -504,7 +504,7 @@ get_kwm_win_icon (MetaDisplay *display, *pixmap = None; *mask = None; - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); icons = NULL; result = XGetWindowProperty (display->xdisplay, xwindow, display->atom__KWM_WIN_ICON, diff --git a/src/core/iconcache.h b/src/x11/iconcache.h index 84143a6..84143a6 100644 --- a/src/core/iconcache.h +++ b/src/x11/iconcache.h diff --git a/src/core/mutter-Xatomtype.h b/src/x11/mutter-Xatomtype.h index 2073bc5..2073bc5 100644 --- a/src/core/mutter-Xatomtype.h +++ b/src/x11/mutter-Xatomtype.h diff --git a/src/core/session.c b/src/x11/session.c index 2a76619..48678ab 100644 --- a/src/core/session.c +++ b/src/x11/session.c @@ -24,6 +24,7 @@ #include <config.h> #include "util-private.h" +#include <meta/main.h> #include "session.h" #include <X11/Xatom.h> @@ -530,6 +531,12 @@ die_callback (SmcConn smc_conn, SmPointer client_data) * Anything that wants us to go away outside of session management * can use kill(). */ + + /* All of that is true - unless we're a wayland compositor. In which + * case the X server won't go down until we do, so we must die first. + */ + if (meta_is_wayland_compositor ()) + meta_quit (0); } static void @@ -839,14 +846,14 @@ save_state (void) if (mkdir (mutter_dir, 0700) < 0 && errno != EEXIST) { - meta_warning (_("Could not create directory '%s': %s\n"), + meta_warning ("Could not create directory '%s': %s\n", mutter_dir, g_strerror (errno)); } if (mkdir (session_dir, 0700) < 0 && errno != EEXIST) { - meta_warning (_("Could not create directory '%s': %s\n"), + meta_warning ("Could not create directory '%s': %s\n", session_dir, g_strerror (errno)); } @@ -856,7 +863,7 @@ save_state (void) if (outfile == NULL) { - meta_warning (_("Could not open session file '%s' for writing: %s\n"), + meta_warning ("Could not open session file '%s' for writing: %s\n", full_save_file (), g_strerror (errno)); goto out; } @@ -997,12 +1004,12 @@ save_state (void) /* FIXME need a dialog for this */ if (ferror (outfile)) { - meta_warning (_("Error writing session file '%s': %s\n"), + meta_warning ("Error writing session file '%s': %s\n", full_save_file (), g_strerror (errno)); } if (fclose (outfile)) { - meta_warning (_("Error closing session file '%s': %s\n"), + meta_warning ("Error closing session file '%s': %s\n", full_save_file (), g_strerror (errno)); } } @@ -1132,7 +1139,7 @@ load_state (const char *previous_save_file) error: - meta_warning (_("Failed to parse saved session file: %s\n"), + meta_warning ("Failed to parse saved session file: %s\n", error->message); g_error_free (error); @@ -1181,7 +1188,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<mutter_session> attribute seen but we already have the session ID")); + "<mutter_session> attribute seen but we already have the session ID"); return; } @@ -1194,7 +1201,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute %s on <%s> element"), + "Unknown attribute %s on <%s> element", name, "mutter_session"); return; } @@ -1211,7 +1218,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("nested <window> tag")); + "nested <window> tag"); return; } @@ -1269,7 +1276,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute %s on <%s> element"), + "Unknown attribute %s on <%s> element", name, "window"); session_info_free (pd->info); pd->info = NULL; @@ -1301,7 +1308,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute %s on <%s> element"), + "Unknown attribute %s on <%s> element", name, "window"); session_info_free (pd->info); pd->info = NULL; @@ -1373,7 +1380,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute %s on <%s> element"), + "Unknown attribute %s on <%s> element", name, "maximized"); return; } @@ -1433,7 +1440,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute %s on <%s> element"), + "Unknown attribute %s on <%s> element", name, "geometry"); return; } @@ -1453,7 +1460,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, - _("Unknown element %s"), + "Unknown element %s", element_name); return; } @@ -1809,7 +1816,7 @@ warn_about_lame_clients_and_finish_interact (gboolean shutdown) "and will have to be restarted manually next time " "you log in."), "240", - meta_get_display()->active_screen->screen_name, + meta_get_display()->screen->screen_name, NULL, NULL, NULL, None, columns, diff --git a/src/core/session.h b/src/x11/session.h index c032ff1..c032ff1 100644 --- a/src/core/session.h +++ b/src/x11/session.h diff --git a/src/core/testasyncgetprop.c b/src/x11/testasyncgetprop.c index 028276c..028276c 100644 --- a/src/core/testasyncgetprop.c +++ b/src/x11/testasyncgetprop.c diff --git a/src/core/window-props.c b/src/x11/window-props.c index 94b12ae..7552251 100644 --- a/src/core/window-props.c +++ b/src/x11/window-props.c @@ -39,6 +39,8 @@ #include <config.h> #include "window-props.h" +#include "window-x11.h" +#include "window-x11-private.h" #include <meta/errors.h> #include "xprops.h" #include "frame.h" @@ -229,7 +231,7 @@ reload_net_wm_window_type (MetaWindow *window, MetaPropValue *value, gboolean initial) { - meta_window_update_net_wm_type (window); + meta_window_x11_update_net_wm_type (window); } static void @@ -302,18 +304,17 @@ reload_gtk_frame_extents (MetaWindow *window, } else { - GtkBorder *extents = &window->custom_frame_extents; - - window->has_custom_frame_extents = TRUE; - extents->left = (int)value->v.cardinal_list.cardinals[0]; - extents->right = (int)value->v.cardinal_list.cardinals[1]; - extents->top = (int)value->v.cardinal_list.cardinals[2]; - extents->bottom = (int)value->v.cardinal_list.cardinals[3]; + GtkBorder extents; + extents.left = (int)value->v.cardinal_list.cardinals[0]; + extents.right = (int)value->v.cardinal_list.cardinals[1]; + extents.top = (int)value->v.cardinal_list.cardinals[2]; + extents.bottom = (int)value->v.cardinal_list.cardinals[3]; + meta_window_set_custom_frame_extents (window, &extents); } } else { - window->has_custom_frame_extents = FALSE; + meta_window_set_custom_frame_extents (window, NULL); } if (!initial) @@ -333,7 +334,7 @@ reload_wm_window_role (MetaWindow *window, MetaPropValue *value, gboolean initial) { - meta_window_update_role (window); + meta_window_x11_update_role (window); } static void @@ -346,7 +347,7 @@ reload_net_wm_pid (MetaWindow *window, gulong cardinal = (int) value->v.cardinal; if (cardinal <= 0) - meta_warning (_("Application set a bogus _NET_WM_PID %lu\n"), + meta_warning ("Application set a bogus _NET_WM_PID %lu\n", cardinal); else { @@ -431,9 +432,8 @@ reload_net_wm_user_time_window (MetaWindow *window, /** * set_title_text: * - * Called by set_window_title() and set_icon_title() to set the value of - * @target to @title. It required and @atom is set, it will update the - * appropriate property. + * Called by set_window_title() to set the value of @target to @title. + * If required and @atom is set, it will update the appropriate property. * * Returns: %TRUE if a new title was set. */ @@ -491,28 +491,22 @@ static void set_window_title (MetaWindow *window, const char *title) { - char *str; - + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = window_x11->priv; + + char *new_title = NULL; + gboolean modified = set_title_text (window, - window->using_net_wm_visible_name, + priv->using_net_wm_visible_name, title, window->display->atom__NET_WM_VISIBLE_NAME, - &window->title); - window->using_net_wm_visible_name = modified; + &new_title); + priv->using_net_wm_visible_name = modified; - /* strndup is a hack since GNU libc has broken %.10s */ - str = g_strndup (window->title, 10); - g_free (window->desc); - window->desc = g_strdup_printf ("0x%lx (%s)", window->xwindow, str); - g_free (str); - - if (window->frame) - meta_ui_set_frame_title (window->screen->ui, - window->frame->xwindow, - window->title); - - g_object_notify (G_OBJECT (window), "title"); + meta_window_set_title (window, new_title); + + g_free (new_title); } static void @@ -520,10 +514,13 @@ reload_net_wm_name (MetaWindow *window, MetaPropValue *value, gboolean initial) { + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = window_x11->priv; + if (value->type != META_PROP_VALUE_INVALID) { set_window_title (window, value->v.str); - window->using_net_wm_name = TRUE; + priv->using_net_wm_name = TRUE; meta_verbose ("Using _NET_WM_NAME for new title of %s: \"%s\"\n", window->desc, window->title); @@ -531,7 +528,7 @@ reload_net_wm_name (MetaWindow *window, else { set_window_title (window, NULL); - window->using_net_wm_name = FALSE; + priv->using_net_wm_name = FALSE; if (!initial) meta_window_reload_property (window, XA_WM_NAME, FALSE); } @@ -542,7 +539,10 @@ reload_wm_name (MetaWindow *window, MetaPropValue *value, gboolean initial) { - if (window->using_net_wm_name) + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = window_x11->priv; + + if (priv->using_net_wm_name) { meta_verbose ("Ignoring WM_NAME \"%s\" as _NET_WM_NAME is set\n", value->v.str); @@ -567,7 +567,7 @@ reload_opaque_region (MetaWindow *window, MetaPropValue *value, gboolean initial) { - meta_window_update_opaque_region_x11 (window); + meta_window_x11_update_opaque_region (window); } static void @@ -614,70 +614,13 @@ reload_mutter_hints (MetaWindow *window, } static void -set_icon_title (MetaWindow *window, - const char *title) -{ - gboolean modified = - set_title_text (window, - window->using_net_wm_visible_icon_name, - title, - window->display->atom__NET_WM_VISIBLE_ICON_NAME, - &window->icon_name); - window->using_net_wm_visible_icon_name = modified; -} - -static void -reload_net_wm_icon_name (MetaWindow *window, - MetaPropValue *value, - gboolean initial) -{ - if (value->type != META_PROP_VALUE_INVALID) - { - set_icon_title (window, value->v.str); - window->using_net_wm_icon_name = TRUE; - - meta_verbose ("Using _NET_WM_ICON_NAME for new title of %s: \"%s\"\n", - window->desc, window->title); - } - else - { - set_icon_title (window, NULL); - window->using_net_wm_icon_name = FALSE; - if (!initial) - meta_window_reload_property (window, XA_WM_ICON_NAME, FALSE); - } -} - -static void -reload_wm_icon_name (MetaWindow *window, - MetaPropValue *value, - gboolean initial) -{ - if (window->using_net_wm_icon_name) - { - meta_verbose ("Ignoring WM_ICON_NAME \"%s\" as _NET_WM_ICON_NAME is set\n", - value->v.str); - return; - } - - if (value->type != META_PROP_VALUE_INVALID) - { - set_icon_title (window, value->v.str); - - meta_verbose ("Using WM_ICON_NAME for new title of %s: \"%s\"\n", - window->desc, window->title); - } - else - { - set_icon_title (window, NULL); - } -} - -static void reload_net_wm_state (MetaWindow *window, MetaPropValue *value, gboolean initial) { + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = window_x11->priv; + int i; /* We know this is only an initial window creation, @@ -695,9 +638,9 @@ reload_net_wm_state (MetaWindow *window, window->maximized_horizontally = FALSE; window->maximized_vertically = FALSE; window->fullscreen = FALSE; - window->wm_state_modal = FALSE; - window->wm_state_skip_taskbar = FALSE; - window->wm_state_skip_pager = FALSE; + priv->wm_state_modal = FALSE; + priv->wm_state_skip_taskbar = FALSE; + priv->wm_state_skip_pager = FALSE; window->wm_state_above = FALSE; window->wm_state_below = FALSE; window->wm_state_demands_attention = FALSE; @@ -717,11 +660,11 @@ reload_net_wm_state (MetaWindow *window, else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_HIDDEN) window->minimize_after_placement = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_MODAL) - window->wm_state_modal = TRUE; + priv->wm_state_modal = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_TASKBAR) - window->wm_state_skip_taskbar = TRUE; + priv->wm_state_skip_taskbar = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_PAGER) - window->wm_state_skip_pager = TRUE; + priv->wm_state_skip_pager = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_FULLSCREEN) window->fullscreen_after_placement = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_ABOVE) @@ -739,7 +682,7 @@ reload_net_wm_state (MetaWindow *window, meta_verbose ("Reloaded _NET_WM_STATE for %s\n", window->desc); - meta_window_recalc_window_type (window); + meta_window_x11_recalc_window_type (window); meta_window_recalc_features (window); } @@ -854,7 +797,7 @@ reload_mwm_hints (MetaWindow *window, meta_window_recalc_features (window); - /* We do all this anyhow at the end of meta_window_new() */ + /* We do all this anyhow at the end of meta_window_x11_new() */ if (!window->constructing) { if (window->decorated) @@ -877,23 +820,15 @@ reload_wm_class (MetaWindow *window, MetaPropValue *value, gboolean initial) { - if (window->res_class) - g_free (window->res_class); - if (window->res_name) - g_free (window->res_name); - - window->res_class = NULL; - window->res_name = NULL; - if (value->type != META_PROP_VALUE_INVALID) - { - if (value->v.class_hint.res_name) - window->res_name = g_strdup (value->v.class_hint.res_name); - - if (value->v.class_hint.res_class) - window->res_class = g_strdup (value->v.class_hint.res_class); - - g_object_notify (G_OBJECT (window), "wm-class"); + { + meta_window_set_wm_class (window, + value->v.class_hint.res_class, + value->v.class_hint.res_name); + } + else + { + meta_window_set_wm_class (window, NULL, NULL); } meta_verbose ("Window %s class: '%s' name: '%s'\n", @@ -1427,7 +1362,7 @@ reload_wm_protocols (MetaWindow *window, window->take_focus = FALSE; window->delete_window = FALSE; - window->net_wm_ping = FALSE; + window->can_ping = FALSE; if (value->type == META_PROP_VALUE_INVALID) return; @@ -1443,7 +1378,7 @@ reload_wm_protocols (MetaWindow *window, window->delete_window = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_PING) - window->net_wm_ping = TRUE; + window->can_ping = TRUE; ++i; } @@ -1458,10 +1393,9 @@ reload_wm_hints (MetaWindow *window, gboolean initial) { Window old_group_leader; - gboolean old_urgent; + gboolean urgent; old_group_leader = window->xgroup_leader; - old_urgent = window->wm_hints_urgent; /* Fill in defaults */ window->input = TRUE; @@ -1469,7 +1403,7 @@ reload_wm_hints (MetaWindow *window, window->xgroup_leader = None; window->wm_hints_pixmap = None; window->wm_hints_mask = None; - window->wm_hints_urgent = FALSE; + urgent = FALSE; if (value->type != META_PROP_VALUE_INVALID) { @@ -1491,7 +1425,7 @@ reload_wm_hints (MetaWindow *window, window->wm_hints_mask = hints->icon_mask; if (hints->flags & XUrgencyHint) - window->wm_hints_urgent = TRUE; + urgent = TRUE; meta_verbose ("Read WM_HINTS input: %d iconic: %d group leader: 0x%lx pixmap: 0x%lx mask: 0x%lx\n", window->input, window->initially_iconic, @@ -1508,20 +1442,7 @@ reload_wm_hints (MetaWindow *window, meta_window_group_leader_changed (window); } - /* - * Do not emit urgency notification on the inital property load - */ - if (!initial && (window->wm_hints_urgent != old_urgent)) - g_object_notify (G_OBJECT (window), "urgent"); - - /* - * Do not emit signal for the initial property load, let the constructor to - * take care of it once the MetaWindow is fully constructed. - * - * Only emit if the property is both changed and set. - */ - if (!initial && window->wm_hints_urgent && !old_urgent) - g_signal_emit_by_name (window->display, "window-marked-urgent", window); + meta_window_set_urgent (window, urgent); meta_icon_cache_property_changed (&window->icon_cache, window->display, @@ -1536,7 +1457,7 @@ reload_transient_for (MetaWindow *window, gboolean initial) { MetaWindow *parent = NULL; - Window transient_for, old_transient_for; + Window transient_for; if (value->type != META_PROP_VALUE_INVALID) { @@ -1545,8 +1466,7 @@ reload_transient_for (MetaWindow *window, parent = meta_display_lookup_x_window (window->display, transient_for); if (!parent) { - meta_warning (_("Invalid WM_TRANSIENT_FOR window 0x%lx specified " - "for %s.\n"), + meta_warning ("Invalid WM_TRANSIENT_FOR window 0x%lx specified for %s.\n", transient_for, window->desc); transient_for = None; } @@ -1556,8 +1476,7 @@ reload_transient_for (MetaWindow *window, { if (parent == window) { - meta_warning (_("WM_TRANSIENT_FOR window 0x%lx for %s " - "would create loop.\n"), + meta_warning ("WM_TRANSIENT_FOR window 0x%lx for %s would create loop.\n", transient_for, window->desc); transient_for = None; break; @@ -1573,10 +1492,6 @@ reload_transient_for (MetaWindow *window, if (transient_for == window->xtransient_for) return; - if (meta_window_appears_focused (window) && window->xtransient_for != None) - meta_window_propagate_focus_appearance (window, FALSE); - - old_transient_for = window->xtransient_for; window->xtransient_for = transient_for; window->transient_parent_is_root_window = @@ -1588,46 +1503,14 @@ reload_transient_for (MetaWindow *window, else meta_verbose ("Window %s is not transient\n", window->desc); - /* may now be a dialog */ - meta_window_recalc_window_type (window); - - if (!window->constructing) + if (window->transient_parent_is_root_window || window->xtransient_for == None) + meta_window_set_transient_for (window, NULL); + else { - /* If the window attaches, detaches, or changes attached - * parents, we need to destroy the MetaWindow and let a new one - * be created (which happens as a side effect of - * meta_window_unmanage()). The condition below is correct - * because we know window->xtransient_for has changed. - */ - if (window->attached || meta_window_should_attach_to_parent (window)) - { - guint32 timestamp; - - window->xtransient_for = old_transient_for; - timestamp = meta_display_get_current_time_roundtrip (window->display); - meta_window_unmanage (window, timestamp); - return; - } + parent = meta_display_lookup_x_window (window->display, + window->xtransient_for); + meta_window_set_transient_for (window, parent); } - - /* update stacking constraints */ - if (!window->override_redirect) - meta_stack_update_transient (window->screen->stack, window); - - /* possibly change its group. We treat being a window's transient as - * equivalent to making it your group leader, to work around shortcomings - * in programs such as xmms-- see #328211. - */ - if (window->xtransient_for != None && - window->xgroup_leader != None && - window->xtransient_for != window->xgroup_leader) - meta_window_group_leader_changed (window); - - if (!window->constructing && !window->override_redirect) - meta_window_queue (window, META_QUEUE_MOVE_RESIZE); - - if (meta_window_appears_focused (window) && window->xtransient_for != None) - meta_window_propagate_focus_appearance (window, TRUE); } static void @@ -1791,8 +1674,6 @@ meta_display_init_window_prop_hooks (MetaDisplay *display) { XA_WM_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_name, TRUE, TRUE }, { display->atom__MUTTER_HINTS, META_PROP_VALUE_TEXT_PROPERTY, reload_mutter_hints, TRUE, TRUE }, { display->atom__NET_WM_OPAQUE_REGION, META_PROP_VALUE_CARDINAL_LIST, reload_opaque_region, TRUE, TRUE }, - { display->atom__NET_WM_ICON_NAME, META_PROP_VALUE_UTF8, reload_net_wm_icon_name, TRUE, FALSE }, - { XA_WM_ICON_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_icon_name, TRUE, FALSE }, { display->atom__NET_WM_DESKTOP, META_PROP_VALUE_CARDINAL, reload_net_wm_desktop, TRUE, FALSE }, { display->atom__NET_STARTUP_ID, META_PROP_VALUE_UTF8, reload_net_startup_id, TRUE, FALSE }, { display->atom__NET_WM_SYNC_REQUEST_COUNTER, META_PROP_VALUE_SYNC_COUNTER_LIST, reload_update_counter, TRUE, TRUE }, @@ -1819,8 +1700,8 @@ meta_display_init_window_prop_hooks (MetaDisplay *display) { display->atom__NET_WM_ICON_GEOMETRY, META_PROP_VALUE_CARDINAL_LIST, reload_icon_geometry, FALSE, FALSE }, { display->atom_WM_CLIENT_LEADER, META_PROP_VALUE_INVALID, complain_about_broken_client, FALSE, FALSE }, { display->atom_SM_CLIENT_ID, META_PROP_VALUE_INVALID, complain_about_broken_client, FALSE, FALSE }, - { display->atom_WM_WINDOW_ROLE, META_PROP_VALUE_INVALID, reload_wm_window_role, FALSE, FALSE }, - { display->atom__NET_WM_WINDOW_TYPE, META_PROP_VALUE_INVALID, reload_net_wm_window_type, FALSE, TRUE }, + { display->atom_WM_WINDOW_ROLE, META_PROP_VALUE_INVALID, reload_wm_window_role, TRUE, FALSE }, + { display->atom__NET_WM_WINDOW_TYPE, META_PROP_VALUE_INVALID, reload_net_wm_window_type, TRUE, TRUE }, { display->atom__NET_WM_STRUT, META_PROP_VALUE_INVALID, reload_struts, FALSE, FALSE }, { display->atom__NET_WM_STRUT_PARTIAL, META_PROP_VALUE_INVALID, reload_struts, FALSE, FALSE }, { display->atom__NET_WM_BYPASS_COMPOSITOR, META_PROP_VALUE_CARDINAL, reload_bypass_compositor, FALSE, FALSE }, diff --git a/src/core/window-props.h b/src/x11/window-props.h index 4ea4271..4ea4271 100644 --- a/src/core/window-props.h +++ b/src/x11/window-props.h diff --git a/src/x11/window-x11-private.h b/src/x11/window-x11-private.h new file mode 100644 index 0000000..e288439 --- /dev/null +++ b/src/x11/window-x11-private.h @@ -0,0 +1,57 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington, Anders Carlsson + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "window-private.h" + +#ifndef META_WINDOW_X11_PRIVATE_H +#define META_WINDOW_X11_PRIVATE_H + +G_BEGIN_DECLS + +typedef struct _MetaWindowX11Private MetaWindowX11Private; + +struct _MetaWindowX11 +{ + MetaWindow parent; + + MetaWindowX11Private *priv; +}; + +struct _MetaWindowX11Private +{ + /* TRUE if the client forced these on */ + guint wm_state_skip_taskbar : 1; + guint wm_state_skip_pager : 1; + + /* Weird "_NET_WM_STATE_MODAL" flag */ + guint wm_state_modal : 1; + + /* Info on which props we got our attributes from */ + guint using_net_wm_name : 1; /* vs. plain wm_name */ + guint using_net_wm_visible_name : 1; /* tracked so we can clear it */ + + Atom type_atom; +}; + +G_END_DECLS + +#endif diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c new file mode 100644 index 0000000..099a55d --- /dev/null +++ b/src/x11/window-x11.c @@ -0,0 +1,2528 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington, Anders Carlsson + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include "window-x11.h" +#include "window-x11-private.h" + +#include <string.h> +#include <X11/Xatom.h> +#include <X11/Xlibint.h> /* For display->resource_mask */ + +#ifdef HAVE_SHAPE +#include <X11/extensions/shape.h> +#endif + +#include <X11/extensions/Xcomposite.h> +#include "core.h" + +#include <meta/common.h> +#include <meta/errors.h> +#include <meta/prefs.h> +#include <meta/meta-cursor-tracker.h> + +#include "frame.h" +#include "window-private.h" +#include "window-props.h" +#include "xprops.h" + +struct _MetaWindowX11Class +{ + MetaWindowClass parent_class; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaWindowX11, meta_window_x11, META_TYPE_WINDOW) + +static void +meta_window_x11_init (MetaWindowX11 *window_x11) +{ + window_x11->priv = meta_window_x11_get_instance_private (window_x11); +} + +static void +send_icccm_message (MetaWindow *window, + Atom atom, + guint32 timestamp) +{ + /* This comment and code are from twm, copyright + * Open Group, Evans & Sutherland, etc. + */ + + /* + * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all + * client messages will have the following form: + * + * event type ClientMessage + * message type _XA_WM_PROTOCOLS + * window tmp->w + * format 32 + * data[0] message atom + * data[1] time stamp + */ + + XClientMessageEvent ev; + + ev.type = ClientMessage; + ev.window = window->xwindow; + ev.message_type = window->display->atom_WM_PROTOCOLS; + ev.format = 32; + ev.data.l[0] = atom; + ev.data.l[1] = timestamp; + + meta_error_trap_push (window->display); + XSendEvent (window->display->xdisplay, + window->xwindow, False, 0, (XEvent*) &ev); + meta_error_trap_pop (window->display); +} + +static Window +read_client_leader (MetaDisplay *display, + Window xwindow) +{ + Window retval = None; + + meta_prop_get_window (display, xwindow, + display->atom_WM_CLIENT_LEADER, + &retval); + + return retval; +} + +typedef struct +{ + Window leader; +} ClientLeaderData; + +static gboolean +find_client_leader_func (MetaWindow *ancestor, + void *data) +{ + ClientLeaderData *d; + + d = data; + + d->leader = read_client_leader (ancestor->display, + ancestor->xwindow); + + /* keep going if no client leader found */ + return d->leader == None; +} + +static void +update_sm_hints (MetaWindow *window) +{ + Window leader; + + window->xclient_leader = None; + window->sm_client_id = NULL; + + /* If not on the current window, we can get the client + * leader from transient parents. If we find a client + * leader, we read the SM_CLIENT_ID from it. + */ + leader = read_client_leader (window->display, window->xwindow); + if (leader == None) + { + ClientLeaderData d; + d.leader = None; + meta_window_foreach_ancestor (window, find_client_leader_func, + &d); + leader = d.leader; + } + + if (leader != None) + { + char *str; + + window->xclient_leader = leader; + + if (meta_prop_get_latin1_string (window->display, leader, + window->display->atom_SM_CLIENT_ID, + &str)) + { + window->sm_client_id = g_strdup (str); + meta_XFree (str); + } + } + else + { + meta_verbose ("Didn't find a client leader for %s\n", window->desc); + + if (!meta_prefs_get_disable_workarounds ()) + { + /* Some broken apps (kdelibs fault?) set SM_CLIENT_ID on the app + * instead of the client leader + */ + char *str; + + str = NULL; + if (meta_prop_get_latin1_string (window->display, window->xwindow, + window->display->atom_SM_CLIENT_ID, + &str)) + { + if (window->sm_client_id == NULL) /* first time through */ + meta_warning ("Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n", + window->desc); + + window->sm_client_id = g_strdup (str); + meta_XFree (str); + } + } + } + + meta_verbose ("Window %s client leader: 0x%lx SM_CLIENT_ID: '%s'\n", + window->desc, window->xclient_leader, + window->sm_client_id ? window->sm_client_id : "none"); +} + +static void +send_configure_notify (MetaWindow *window) +{ + XEvent event; + + /* from twm */ + + event.type = ConfigureNotify; + event.xconfigure.display = window->display->xdisplay; + event.xconfigure.event = window->xwindow; + event.xconfigure.window = window->xwindow; + event.xconfigure.x = window->rect.x - window->border_width; + event.xconfigure.y = window->rect.y - window->border_width; + if (window->frame) + { + if (window->withdrawn) + { + MetaFrameBorders borders; + /* We reparent the client window and put it to the position + * where the visible top-left of the frame window currently is. + */ + + meta_frame_calc_borders (window->frame, &borders); + + event.xconfigure.x = window->frame->rect.x + borders.invisible.left; + event.xconfigure.y = window->frame->rect.y + borders.invisible.top; + } + else + { + /* Need to be in root window coordinates */ + event.xconfigure.x += window->frame->rect.x; + event.xconfigure.y += window->frame->rect.y; + } + } + event.xconfigure.width = window->rect.width; + event.xconfigure.height = window->rect.height; + event.xconfigure.border_width = window->border_width; /* requested not actual */ + event.xconfigure.above = None; /* FIXME */ + event.xconfigure.override_redirect = False; + + meta_topic (META_DEBUG_GEOMETRY, + "Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d\n", + window->desc, + event.xconfigure.x, event.xconfigure.y, + event.xconfigure.width, event.xconfigure.height); + + meta_error_trap_push (window->display); + XSendEvent (window->display->xdisplay, + window->xwindow, + False, StructureNotifyMask, &event); + meta_error_trap_pop (window->display); +} + +static void +meta_window_x11_manage (MetaWindow *window) +{ + MetaDisplay *display = window->display; + + meta_display_register_x_window (display, &window->xwindow, window); + meta_window_x11_update_shape_region (window); + meta_window_x11_update_input_region (window); + + /* assign the window to its group, or create a new group if needed */ + window->group = NULL; + window->xgroup_leader = None; + meta_window_compute_group (window); + + meta_window_load_initial_properties (window); + + if (!window->override_redirect) + update_sm_hints (window); /* must come after transient_for */ + + meta_window_x11_update_net_wm_type (window); +} + +static void +meta_window_x11_unmanage (MetaWindow *window) +{ + meta_error_trap_push (window->display); + + if (window->withdrawn) + { + /* We need to clean off the window's state so it + * won't be restored if the app maps it again. + */ + meta_verbose ("Cleaning state from window %s\n", window->desc); + XDeleteProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_DESKTOP); + XDeleteProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_STATE); + XDeleteProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_FULLSCREEN_MONITORS); + meta_window_x11_set_wm_state (window); + } + else + { + /* We need to put WM_STATE so that others will understand it on + * restart. + */ + if (!window->minimized) + meta_window_x11_set_wm_state (window); + + /* If we're unmanaging a window that is not withdrawn, then + * either (a) mutter is exiting, in which case we need to map + * the window so the next WM will know that it's not Withdrawn, + * or (b) we want to create a new MetaWindow to replace the + * current one, which will happen automatically if we re-map + * the X Window. + */ + XMapWindow (window->display->xdisplay, + window->xwindow); + } + + meta_display_unregister_x_window (window->display, window->xwindow); + + /* Put back anything we messed up */ + if (window->border_width != 0) + XSetWindowBorderWidth (window->display->xdisplay, + window->xwindow, + window->border_width); + + /* No save set */ + XRemoveFromSaveSet (window->display->xdisplay, + window->xwindow); + + /* Even though the window is now unmanaged, we can't unselect events. This + * window might be a window from this process, like a GdkMenu, in + * which case it will have pointer events and so forth selected + * for it by GDK. There's no way to disentangle those events from the events + * we've selected. Even for a window from a different X client, + * GDK could also have selected events for it for IPC purposes, so we + * can't unselect in that case either. + * + * Similarly, we can't unselected for events on window->user_time_window. + * It might be our own GDK focus window, or it might be a window that a + * different client is using for multiple different things: + * _NET_WM_USER_TIME_WINDOW and IPC, perhaps. + */ + + if (window->user_time_window != None) + { + meta_display_unregister_x_window (window->display, + window->user_time_window); + window->user_time_window = None; + } + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (window->display)) + XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask); +#endif + + /* The XReparentWindow call in meta_window_destroy_frame() moves the + * window so we need to send a configure notify; see bug 399552. (We + * also do this just in case a window got unmaximized.) + */ + send_configure_notify (window); + + meta_error_trap_pop (window->display); +} + +static void +meta_window_x11_ping (MetaWindow *window, + guint32 serial) +{ + MetaDisplay *display = window->display; + + send_icccm_message (window, display->atom__NET_WM_PING, serial); +} + +static void +meta_window_x11_delete (MetaWindow *window, + guint32 timestamp) +{ + meta_error_trap_push (window->display); + if (window->delete_window) + { + meta_topic (META_DEBUG_WINDOW_OPS, + "Deleting %s with delete_window request\n", + window->desc); + send_icccm_message (window, window->display->atom_WM_DELETE_WINDOW, timestamp); + } + else + { + meta_topic (META_DEBUG_WINDOW_OPS, + "Deleting %s with explicit kill\n", + window->desc); + XKillClient (window->display->xdisplay, window->xwindow); + } + meta_error_trap_pop (window->display); +} + +static void +meta_window_x11_kill (MetaWindow *window) +{ + meta_topic (META_DEBUG_WINDOW_OPS, + "Killing %s brutally\n", + window->desc); + + if (!meta_window_is_remote (window) && + window->net_wm_pid > 0) + { + meta_topic (META_DEBUG_WINDOW_OPS, + "Killing %s with kill()\n", + window->desc); + + if (kill (window->net_wm_pid, 9) < 0) + meta_topic (META_DEBUG_WINDOW_OPS, + "Failed to signal %s: %s\n", + window->desc, strerror (errno)); + } + + meta_topic (META_DEBUG_WINDOW_OPS, + "Disconnecting %s with XKillClient()\n", + window->desc); + + meta_error_trap_push (window->display); + XKillClient (window->display->xdisplay, window->xwindow); + meta_error_trap_pop (window->display); +} + +static void +request_take_focus (MetaWindow *window, + guint32 timestamp) +{ + MetaDisplay *display = window->display; + + meta_topic (META_DEBUG_FOCUS, "WM_TAKE_FOCUS(%s, %u)\n", + window->desc, timestamp); + + send_icccm_message (window, display->atom_WM_TAKE_FOCUS, timestamp); +} + +static void +meta_window_x11_focus (MetaWindow *window, + guint32 timestamp) +{ + /* For output-only or shaded windows, focus the frame. + * This seems to result in the client window getting key events + * though, so I don't know if it's icccm-compliant. + * + * Still, we have to do this or keynav breaks for these windows. + */ + if (window->frame && + (window->shaded || + !(window->input || window->take_focus))) + { + if (window->frame) + { + meta_topic (META_DEBUG_FOCUS, + "Focusing frame of %s\n", window->desc); + meta_display_set_input_focus_window (window->display, + window, + TRUE, + timestamp); + } + } + else + { + if (window->input) + { + meta_topic (META_DEBUG_FOCUS, + "Setting input focus on %s since input = true\n", + window->desc); + meta_display_set_input_focus_window (window->display, + window, + FALSE, + timestamp); + } + + if (window->take_focus) + { + meta_topic (META_DEBUG_FOCUS, + "Sending WM_TAKE_FOCUS to %s since take_focus = true\n", + window->desc); + + if (!window->input) + { + /* The "Globally Active Input" window case, where the window + * doesn't want us to call XSetInputFocus on it, but does + * want us to send a WM_TAKE_FOCUS. + * + * Normally, we want to just leave the focus undisturbed until + * the window respnds to WM_TAKE_FOCUS, but if we're unmanaging + * the current focus window we *need* to move the focus away, so + * we focus the no_focus_window now (and set + * display->focus_window to that) before sending WM_TAKE_FOCUS. + */ + if (window->display->focus_window != NULL && + window->display->focus_window->unmanaging) + meta_display_focus_the_no_focus_window (window->display, + window->screen, + timestamp); + } + + request_take_focus (window, timestamp); + } + } +} + +static void +update_net_frame_extents (MetaWindow *window) +{ + unsigned long data[4]; + MetaFrameBorders borders; + + meta_frame_calc_borders (window->frame, &borders); + /* Left */ + data[0] = borders.visible.left; + /* Right */ + data[1] = borders.visible.right; + /* Top */ + data[2] = borders.visible.top; + /* Bottom */ + data[3] = borders.visible.bottom; + + meta_topic (META_DEBUG_GEOMETRY, + "Setting _NET_FRAME_EXTENTS on managed window 0x%lx " + "to left = %lu, right = %lu, top = %lu, bottom = %lu\n", + window->xwindow, data[0], data[1], data[2], data[3]); + + meta_error_trap_push (window->display); + XChangeProperty (window->display->xdisplay, window->xwindow, + window->display->atom__NET_FRAME_EXTENTS, + XA_CARDINAL, + 32, PropModeReplace, (guchar*) data, 4); + meta_error_trap_pop (window->display); +} + +#ifdef HAVE_XSYNC +static gboolean +sync_request_timeout (gpointer data) +{ + MetaWindow *window = data; + + window->sync_request_timeout_id = 0; + + /* We have now waited for more than a second for the + * application to respond to the sync request + */ + window->disable_sync = TRUE; + + /* Reset the wait serial, so we don't continue freezing + * window updates + */ + window->sync_request_wait_serial = 0; + meta_compositor_set_updates_frozen (window->display->compositor, window, + meta_window_updates_are_frozen (window)); + + if (window == window->display->grab_window && + meta_grab_op_is_resizing (window->display->grab_op)) + { + meta_window_update_resize (window, + window->display->grab_last_user_action_was_snap, + window->display->grab_latest_motion_x, + window->display->grab_latest_motion_y, + TRUE); + } + + return FALSE; +} + +static void +send_sync_request (MetaWindow *window) +{ + XClientMessageEvent ev; + gint64 wait_serial; + + /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to + * increase the value, but for the new "extended" style we need to + * pick an even (unfrozen) value sufficiently ahead of the last serial + * that we received from the client; the same code still works + * for the old style. The increment of 240 is specified by the EWMH + * and is (1 second) * (60fps) * (an increment of 4 per frame). + */ + wait_serial = window->sync_request_serial + 240; + + window->sync_request_wait_serial = wait_serial; + + ev.type = ClientMessage; + ev.window = window->xwindow; + ev.message_type = window->display->atom_WM_PROTOCOLS; + ev.format = 32; + ev.data.l[0] = window->display->atom__NET_WM_SYNC_REQUEST; + /* FIXME: meta_display_get_current_time() is bad, but since calls + * come from meta_window_move_resize_internal (which in turn come + * from all over), I'm not sure what we can do to fix it. Do we + * want to use _roundtrip, though? + */ + ev.data.l[1] = meta_display_get_current_time (window->display); + ev.data.l[2] = wait_serial & G_GUINT64_CONSTANT(0xffffffff); + ev.data.l[3] = wait_serial >> 32; + ev.data.l[4] = window->extended_sync_request_counter ? 1 : 0; + + /* We don't need to trap errors here as we are already + * inside an error_trap_push()/pop() pair. + */ + XSendEvent (window->display->xdisplay, + window->xwindow, False, 0, (XEvent*) &ev); + + /* We give the window 1 sec to respond to _NET_WM_SYNC_REQUEST; + * if this time expires, we consider the window unresponsive + * and resize it unsynchonized. + */ + window->sync_request_timeout_id = g_timeout_add (1000, + sync_request_timeout, + window); + + meta_compositor_set_updates_frozen (window->display->compositor, window, + meta_window_updates_are_frozen (window)); +} +#endif + +static void +meta_window_x11_move_resize_internal (MetaWindow *window, + int gravity, + MetaRectangle requested_rect, + MetaRectangle constrained_rect, + MetaMoveResizeFlags flags, + MetaMoveResizeResultFlags *result) +{ + int root_x_nw, root_y_nw; + int w, h; + int client_move_x, client_move_y; + int size_dx, size_dy; + XWindowChanges values; + unsigned int mask; + gboolean need_configure_notify; + MetaFrameBorders borders; + gboolean need_move_client = FALSE; + gboolean need_move_frame = FALSE; + gboolean need_resize_client = FALSE; + gboolean need_resize_frame = FALSE; + gboolean frame_shape_changed = FALSE; + gboolean configure_frame_first; + + gboolean is_configure_request; + + is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0; + + /* meta_window_constrain() might have maximized the window after placement, + * changing the borders. + */ + meta_frame_calc_borders (window->frame, &borders); + + root_x_nw = constrained_rect.x; + root_y_nw = constrained_rect.y; + w = constrained_rect.width; + h = constrained_rect.height; + + if (w != window->rect.width || + h != window->rect.height) + need_resize_client = TRUE; + + window->rect.width = w; + window->rect.height = h; + + if (window->frame) + { + int frame_size_dx, frame_size_dy; + int new_w, new_h; + + new_w = window->rect.width + borders.total.left + borders.total.right; + + if (window->shaded) + new_h = borders.total.top; + else + new_h = window->rect.height + borders.total.top + borders.total.bottom; + + frame_size_dx = new_w - window->frame->rect.width; + frame_size_dy = new_h - window->frame->rect.height; + + need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0); + + window->frame->rect.width = new_w; + window->frame->rect.height = new_h; + + meta_topic (META_DEBUG_GEOMETRY, + "Calculated frame size %dx%d\n", + window->frame->rect.width, + window->frame->rect.height); + } + + /* For nice effect, when growing the window we want to move/resize + * the frame first, when shrinking the window we want to move/resize + * the client first. If we grow one way and shrink the other, + * see which way we're moving "more" + * + * Mail from Owen subject "Suggestion: Gravity and resizing from the left" + * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html + * + * An annoying fact you need to know in this code is that StaticGravity + * does nothing if you _only_ resize or _only_ move the frame; + * it must move _and_ resize, otherwise you get NorthWestGravity + * behavior. The move and resize must actually occur, it is not + * enough to set CWX | CWWidth but pass in the current size/pos. + */ + + if (window->frame) + { + int new_x, new_y; + int frame_pos_dx, frame_pos_dy; + + /* Compute new frame coords */ + new_x = root_x_nw - borders.total.left; + new_y = root_y_nw - borders.total.top; + + frame_pos_dx = new_x - window->frame->rect.x; + frame_pos_dy = new_y - window->frame->rect.y; + + need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0); + + window->frame->rect.x = new_x; + window->frame->rect.y = new_y; + + /* If frame will both move and resize, then StaticGravity + * on the child window will kick in and implicitly move + * the child with respect to the frame. The implicit + * move will keep the child in the same place with + * respect to the root window. If frame only moves + * or only resizes, then the child will just move along + * with the frame. + */ + + /* window->rect.x, window->rect.y are relative to frame, + * remember they are the server coords + */ + + new_x = borders.total.left; + new_y = borders.total.top; + client_move_x = new_x; + client_move_y = new_y; + + if (client_move_x != window->rect.x || + client_move_y != window->rect.y) + need_move_client = TRUE; + + /* This is the final target position, but not necessarily what + * we pass to XConfigureWindow, due to StaticGravity implicit + * movement. + */ + window->rect.x = new_x; + window->rect.y = new_y; + } + else + { + if (root_x_nw != window->rect.x || + root_y_nw != window->rect.y) + need_move_client = TRUE; + + window->rect.x = root_x_nw; + window->rect.y = root_y_nw; + + client_move_x = window->rect.x; + client_move_y = window->rect.y; + } + + /* If frame extents have changed, fill in other frame fields and + change frame's extents property. */ + if (window->frame && + (window->frame->child_x != borders.total.left || + window->frame->child_y != borders.total.top || + window->frame->right_width != borders.total.right || + window->frame->bottom_height != borders.total.bottom)) + { + window->frame->child_x = borders.total.left; + window->frame->child_y = borders.total.top; + window->frame->right_width = borders.total.right; + window->frame->bottom_height = borders.total.bottom; + + update_net_frame_extents (window); + } + + /* See ICCCM 4.1.5 for when to send ConfigureNotify */ + + need_configure_notify = FALSE; + + /* If this is a configure request and we change nothing, then we + * must send configure notify. + */ + if (is_configure_request && + !(need_move_client || need_move_frame || + need_resize_client || need_resize_frame || + window->border_width != 0)) + need_configure_notify = TRUE; + + /* We must send configure notify if we move but don't resize, since + * the client window may not get a real event + */ + if ((need_move_client || need_move_frame) && + !(need_resize_client || need_resize_frame)) + need_configure_notify = TRUE; + + /* MapRequest events with a PPosition or UPosition hint with a frame + * are moved by mutter without resizing; send a configure notify + * in such cases. See #322840. (Note that window->constructing is + * only true iff this call is due to a MapRequest, and when + * PPosition/UPosition hints aren't set, mutter seems to send a + * ConfigureNotify anyway due to the above code.) + */ + if (window->constructing && window->frame && + ((window->size_hints.flags & PPosition) || + (window->size_hints.flags & USPosition))) + need_configure_notify = TRUE; + + /* The rest of this function syncs our new size/pos with X as + * efficiently as possible + */ + + /* Normally, we configure the frame first depending on whether + * we grow the frame more than we shrink. The idea is to avoid + * messing up the window contents by having a temporary situation + * where the frame is smaller than the window. However, if we're + * cooperating with the client to create an atomic frame upate, + * and the window is redirected, then we should always update + * the frame first, since updating the frame will force a new + * backing pixmap to be allocated, and the old backing pixmap + * will be left undisturbed for us to paint to the screen until + * the client finishes redrawing. + */ + if (window->extended_sync_request_counter) + { + configure_frame_first = TRUE; + } + else + { + size_dx = w - window->rect.width; + size_dy = h - window->rect.height; + + configure_frame_first = size_dx + size_dy >= 0; + } + + if (configure_frame_first && window->frame) + frame_shape_changed = meta_frame_sync_to_window (window->frame, + gravity, + need_move_frame, need_resize_frame); + + values.border_width = 0; + values.x = client_move_x; + values.y = client_move_y; + values.width = window->rect.width; + values.height = window->rect.height; + + mask = 0; + if (is_configure_request && window->border_width != 0) + mask |= CWBorderWidth; /* must force to 0 */ + if (need_move_client) + mask |= (CWX | CWY); + if (need_resize_client) + mask |= (CWWidth | CWHeight); + + if (mask != 0) + { + { + int newx, newy; + meta_window_get_position (window, &newx, &newy); + meta_topic (META_DEBUG_GEOMETRY, + "Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n", + newx, newy, + window->rect.width, window->rect.height, + mask & CWBorderWidth ? "true" : "false", + need_move_client ? "true" : "false", + need_resize_client ? "true" : "false"); + } + + meta_error_trap_push (window->display); + +#ifdef HAVE_XSYNC + if (window == window->display->grab_window && + meta_grab_op_is_resizing (window->display->grab_op) && + !window->disable_sync && + window->sync_request_counter != None && + window->sync_request_alarm != None && + window->sync_request_timeout_id == 0) + { + send_sync_request (window); + } +#endif + + XConfigureWindow (window->display->xdisplay, + window->xwindow, + mask, + &values); + + meta_error_trap_pop (window->display); + } + + if (!configure_frame_first && window->frame) + frame_shape_changed = meta_frame_sync_to_window (window->frame, + gravity, + need_move_frame, need_resize_frame); + + if (need_configure_notify) + send_configure_notify (window); + + if (frame_shape_changed) + *result |= META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED; + if (need_move_client || need_move_frame) + *result |= META_MOVE_RESIZE_RESULT_MOVED; + if (need_resize_client || need_resize_frame) + *result |= META_MOVE_RESIZE_RESULT_RESIZED; +} + +static void +meta_window_x11_get_default_skip_hints (MetaWindow *window, + gboolean *skip_taskbar_out, + gboolean *skip_pager_out) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + + *skip_taskbar_out = priv->wm_state_skip_taskbar; + *skip_pager_out = priv->wm_state_skip_pager; +} + +static void +meta_window_x11_class_init (MetaWindowX11Class *klass) +{ + MetaWindowClass *window_class = META_WINDOW_CLASS (klass); + + window_class->manage = meta_window_x11_manage; + window_class->unmanage = meta_window_x11_unmanage; + window_class->ping = meta_window_x11_ping; + window_class->delete = meta_window_x11_delete; + window_class->kill = meta_window_x11_kill; + window_class->focus = meta_window_x11_focus; + window_class->move_resize_internal = meta_window_x11_move_resize_internal; + window_class->get_default_skip_hints = meta_window_x11_get_default_skip_hints; +} + +void +meta_window_x11_set_net_wm_state (MetaWindow *window) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + int i; + unsigned long data[13]; + + i = 0; + if (window->shaded) + { + data[i] = window->display->atom__NET_WM_STATE_SHADED; + ++i; + } + if (priv->wm_state_modal) + { + data[i] = window->display->atom__NET_WM_STATE_MODAL; + ++i; + } + if (window->skip_pager) + { + data[i] = window->display->atom__NET_WM_STATE_SKIP_PAGER; + ++i; + } + if (window->skip_taskbar) + { + data[i] = window->display->atom__NET_WM_STATE_SKIP_TASKBAR; + ++i; + } + if (window->maximized_horizontally) + { + data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_HORZ; + ++i; + } + if (window->maximized_vertically) + { + data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_VERT; + ++i; + } + if (window->fullscreen) + { + data[i] = window->display->atom__NET_WM_STATE_FULLSCREEN; + ++i; + } + if (!meta_window_showing_on_its_workspace (window) || window->shaded) + { + data[i] = window->display->atom__NET_WM_STATE_HIDDEN; + ++i; + } + if (window->wm_state_above) + { + data[i] = window->display->atom__NET_WM_STATE_ABOVE; + ++i; + } + if (window->wm_state_below) + { + data[i] = window->display->atom__NET_WM_STATE_BELOW; + ++i; + } + if (window->wm_state_demands_attention) + { + data[i] = window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION; + ++i; + } + if (window->on_all_workspaces_requested) + { + data[i] = window->display->atom__NET_WM_STATE_STICKY; + ++i; + } + if (meta_window_appears_focused (window)) + { + data[i] = window->display->atom__NET_WM_STATE_FOCUSED; + ++i; + } + + meta_verbose ("Setting _NET_WM_STATE with %d atoms\n", i); + + meta_error_trap_push (window->display); + XChangeProperty (window->display->xdisplay, window->xwindow, + window->display->atom__NET_WM_STATE, + XA_ATOM, + 32, PropModeReplace, (guchar*) data, i); + meta_error_trap_pop (window->display); + + if (window->fullscreen) + { + if (window->fullscreen_monitors[0] >= 0) + { + data[0] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[0]); + data[1] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[1]); + data[2] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[2]); + data[3] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[3]); + + meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n"); + meta_error_trap_push (window->display); + XChangeProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_FULLSCREEN_MONITORS, + XA_CARDINAL, 32, PropModeReplace, + (guchar*) data, 4); + meta_error_trap_pop (window->display); + } + else + { + meta_verbose ("Clearing _NET_WM_FULLSCREEN_MONITORS\n"); + meta_error_trap_push (window->display); + XDeleteProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_FULLSCREEN_MONITORS); + meta_error_trap_pop (window->display); + } + } +} + +void +meta_window_x11_update_net_wm_type (MetaWindow *window) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + int n_atoms; + Atom *atoms; + int i; + + priv->type_atom = None; + n_atoms = 0; + atoms = NULL; + + meta_prop_get_atom_list (window->display, window->xwindow, + window->display->atom__NET_WM_WINDOW_TYPE, + &atoms, &n_atoms); + + i = 0; + while (i < n_atoms) + { + /* We break as soon as we find one we recognize, + * supposed to prefer those near the front of the list + */ + if (atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DOCK || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_MENU || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG || + atoms[i] == + window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP || + atoms[i] == + window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_COMBO || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DND || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL) + { + priv->type_atom = atoms[i]; + break; + } + + ++i; + } + + meta_XFree (atoms); + + if (meta_is_verbose ()) + { + char *str; + + str = NULL; + if (priv->type_atom != None) + { + meta_error_trap_push (window->display); + str = XGetAtomName (window->display->xdisplay, priv->type_atom); + meta_error_trap_pop (window->display); + } + + meta_verbose ("Window %s type atom %s\n", window->desc, + str ? str : "(none)"); + + if (str) + meta_XFree (str); + } + + meta_window_x11_recalc_window_type (window); +} + +void +meta_window_x11_update_role (MetaWindow *window) +{ + char *str; + + g_return_if_fail (!window->override_redirect); + + if (window->role) + g_free (window->role); + window->role = NULL; + + if (meta_prop_get_latin1_string (window->display, window->xwindow, + window->display->atom_WM_WINDOW_ROLE, + &str)) + { + window->role = g_strdup (str); + meta_XFree (str); + } + + meta_verbose ("Updated role of %s to '%s'\n", + window->desc, window->role ? window->role : "null"); +} + +static void +meta_window_set_opaque_region (MetaWindow *window, + cairo_region_t *region) +{ + g_clear_pointer (&window->opaque_region, cairo_region_destroy); + + if (region != NULL) + window->opaque_region = cairo_region_reference (region); + + meta_compositor_window_shape_changed (window->display->compositor, window); +} + +void +meta_window_x11_update_opaque_region (MetaWindow *window) +{ + cairo_region_t *opaque_region = NULL; + gulong *region = NULL; + int nitems; + + if (meta_prop_get_cardinal_list (window->display, + window->xwindow, + window->display->atom__NET_WM_OPAQUE_REGION, + ®ion, &nitems)) + { + cairo_rectangle_int_t *rects; + int i, rect_index, nrects; + + if (nitems % 4 != 0) + { + meta_verbose ("_NET_WM_OPAQUE_REGION does not have a list of 4-tuples."); + goto out; + } + + /* empty region */ + if (nitems == 0) + goto out; + + nrects = nitems / 4; + + rects = g_new (cairo_rectangle_int_t, nrects); + + rect_index = 0; + i = 0; + while (i < nitems) + { + cairo_rectangle_int_t *rect = &rects[rect_index]; + + rect->x = region[i++]; + rect->y = region[i++]; + rect->width = region[i++]; + rect->height = region[i++]; + + rect_index++; + } + + opaque_region = cairo_region_create_rectangles (rects, nrects); + + g_free (rects); + } + + out: + meta_XFree (region); + + meta_window_set_opaque_region (window, opaque_region); + cairo_region_destroy (opaque_region); +} + +static cairo_region_t * +region_create_from_x_rectangles (const XRectangle *rects, + int n_rects) +{ + int i; + cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects); + + for (i = 0; i < n_rects; i ++) + { + cairo_rects[i].x = rects[i].x; + cairo_rects[i].y = rects[i].y; + cairo_rects[i].width = rects[i].width; + cairo_rects[i].height = rects[i].height; + } + + return cairo_region_create_rectangles (cairo_rects, n_rects); +} + +static void +meta_window_set_input_region (MetaWindow *window, + cairo_region_t *region) +{ + g_clear_pointer (&window->input_region, cairo_region_destroy); + + if (region != NULL) + window->input_region = cairo_region_reference (region); + + meta_compositor_window_shape_changed (window->display->compositor, window); +} + +#if 0 +/* Print out a region; useful for debugging */ +static void +print_region (cairo_region_t *region) +{ + int n_rects; + int i; + + n_rects = cairo_region_num_rectangles (region); + g_print ("["); + for (i = 0; i < n_rects; i++) + { + cairo_rectangle_int_t rect; + cairo_region_get_rectangle (region, i, &rect); + g_print ("+%d+%dx%dx%d ", + rect.x, rect.y, rect.width, rect.height); + } + g_print ("]\n"); +} +#endif + +void +meta_window_x11_update_input_region (MetaWindow *window) +{ + cairo_region_t *region = NULL; + + /* Decorated windows don't have an input region, because + we don't shape the frame to match the client windows + (so the events are blocked by the frame anyway) + */ + if (window->decorated) + { + if (window->input_region) + meta_window_set_input_region (window, NULL); + return; + } + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (window->display)) + { + /* Translate the set of XShape rectangles that we + * get from the X server to a cairo_region. */ + XRectangle *rects = NULL; + int n_rects, ordering; + + meta_error_trap_push (window->display); + rects = XShapeGetRectangles (window->display->xdisplay, + window->xwindow, + ShapeInput, + &n_rects, + &ordering); + meta_error_trap_pop (window->display); + + /* XXX: The x shape extension doesn't provide a way to only test if an + * input shape has been specified, so we have to query and throw away the + * rectangles. */ + if (rects) + { + if (n_rects > 1 || + (n_rects == 1 && + (rects[0].x != 0 || + rects[0].y != 0 || + rects[0].width != window->rect.width || + rects[0].height != window->rect.height))) + region = region_create_from_x_rectangles (rects, n_rects); + + XFree (rects); + } + } +#endif /* HAVE_SHAPE */ + + if (region != NULL) + { + cairo_rectangle_int_t client_area; + + client_area.x = 0; + client_area.y = 0; + client_area.width = window->rect.width; + client_area.height = window->rect.height; + + /* The shape we get back from the client may have coordinates + * outside of the frame. The X SHAPE Extension requires that + * the overall shape the client provides never exceeds the + * "bounding rectangle" of the window -- the shape that the + * window would have gotten if it was unshaped. In our case, + * this is simply the client area. + */ + cairo_region_intersect_rectangle (region, &client_area); + } + + meta_window_set_input_region (window, region); + cairo_region_destroy (region); +} + +static void +meta_window_set_shape_region (MetaWindow *window, + cairo_region_t *region) +{ + g_clear_pointer (&window->shape_region, cairo_region_destroy); + + if (region != NULL) + window->shape_region = cairo_region_reference (region); + + meta_compositor_window_shape_changed (window->display->compositor, window); +} + +void +meta_window_x11_update_shape_region (MetaWindow *window) +{ + cairo_region_t *region = NULL; + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (window->display)) + { + /* Translate the set of XShape rectangles that we + * get from the X server to a cairo_region. */ + XRectangle *rects = NULL; + int n_rects, ordering; + + int x_bounding, y_bounding, x_clip, y_clip; + unsigned w_bounding, h_bounding, w_clip, h_clip; + int bounding_shaped, clip_shaped; + + meta_error_trap_push (window->display); + XShapeQueryExtents (window->display->xdisplay, window->xwindow, + &bounding_shaped, &x_bounding, &y_bounding, + &w_bounding, &h_bounding, + &clip_shaped, &x_clip, &y_clip, + &w_clip, &h_clip); + + if (bounding_shaped) + { + rects = XShapeGetRectangles (window->display->xdisplay, + window->xwindow, + ShapeBounding, + &n_rects, + &ordering); + } + meta_error_trap_pop (window->display); + + if (rects) + { + region = region_create_from_x_rectangles (rects, n_rects); + XFree (rects); + } + } +#endif /* HAVE_SHAPE */ + + if (region != NULL) + { + cairo_rectangle_int_t client_area; + + client_area.x = 0; + client_area.y = 0; + client_area.width = window->rect.width; + client_area.height = window->rect.height; + + /* The shape we get back from the client may have coordinates + * outside of the frame. The X SHAPE Extension requires that + * the overall shape the client provides never exceeds the + * "bounding rectangle" of the window -- the shape that the + * window would have gotten if it was unshaped. In our case, + * this is simply the client area. + */ + cairo_region_intersect_rectangle (region, &client_area); + } + + meta_window_set_shape_region (window, region); + cairo_region_destroy (region); +} + +/* Generally meta_window_same_application() is a better idea + * of "sameness", since it handles the case where multiple apps + * want to look like the same app or the same app wants to look + * like multiple apps, but in the case of workarounds for legacy + * applications (which likely aren't setting the group properly + * anyways), it may be desirable to check this as well. + */ +static gboolean +meta_window_same_client (MetaWindow *window, + MetaWindow *other_window) +{ + int resource_mask = window->display->xdisplay->resource_mask; + + return ((window->xwindow & ~resource_mask) == + (other_window->xwindow & ~resource_mask)); +} + +gboolean +meta_window_x11_configure_request (MetaWindow *window, + XEvent *event) +{ + /* Note that x, y is the corner of the window border, + * and width, height is the size of the window inside + * its border, but that we always deny border requests + * and give windows a border of 0. But we save the + * requested border here. + */ + if (event->xconfigurerequest.value_mask & CWBorderWidth) + window->border_width = event->xconfigurerequest.border_width; + + meta_window_move_resize_request(window, + event->xconfigurerequest.value_mask, + window->size_hints.win_gravity, + event->xconfigurerequest.x, + event->xconfigurerequest.y, + event->xconfigurerequest.width, + event->xconfigurerequest.height); + + /* Handle stacking. We only handle raises/lowers, mostly because + * stack.c really can't deal with anything else. I guess we'll fix + * that if a client turns up that really requires it. Only a very + * few clients even require the raise/lower (and in fact all client + * attempts to deal with stacking order are essentially broken, + * since they have no idea what other clients are involved or how + * the stack looks). + * + * I'm pretty sure no interesting client uses TopIf, BottomIf, or + * Opposite anyway, so the only possible missing thing is + * Above/Below with a sibling set. For now we just pretend there's + * never a sibling set and always do the full raise/lower instead of + * the raise-just-above/below-sibling. + */ + if (event->xconfigurerequest.value_mask & CWStackMode) + { + MetaWindow *active_window; + active_window = window->display->focus_window; + if (meta_prefs_get_disable_workarounds ()) + { + meta_topic (META_DEBUG_STACK, + "%s sent an xconfigure stacking request; this is " + "broken behavior and the request is being ignored.\n", + window->desc); + } + else if (active_window && + !meta_window_same_application (window, active_window) && + !meta_window_same_client (window, active_window) && + XSERVER_TIME_IS_BEFORE (window->net_wm_user_time, + active_window->net_wm_user_time)) + { + meta_topic (META_DEBUG_STACK, + "Ignoring xconfigure stacking request from %s (with " + "user_time %u); currently active application is %s (with " + "user_time %u).\n", + window->desc, + window->net_wm_user_time, + active_window->desc, + active_window->net_wm_user_time); + if (event->xconfigurerequest.detail == Above) + meta_window_set_demands_attention(window); + } + else + { + switch (event->xconfigurerequest.detail) + { + case Above: + meta_window_raise (window); + break; + case Below: + meta_window_lower (window); + break; + case TopIf: + case BottomIf: + case Opposite: + break; + } + } + } + + return TRUE; +} + +static gboolean +process_property_notify (MetaWindow *window, + XPropertyEvent *event) +{ + Window xid = window->xwindow; + + if (meta_is_verbose ()) /* avoid looking up the name if we don't have to */ + { + char *property_name = XGetAtomName (window->display->xdisplay, + event->atom); + + meta_verbose ("Property notify on %s for %s\n", + window->desc, property_name); + XFree (property_name); + } + + if (event->atom == window->display->atom__NET_WM_USER_TIME && + window->user_time_window) + { + xid = window->user_time_window; + } + + meta_window_reload_property_from_xwindow (window, xid, event->atom, FALSE); + + return TRUE; +} + +gboolean +meta_window_x11_property_notify (MetaWindow *window, + XEvent *event) +{ + return process_property_notify (window, &event->xproperty); +} + +#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 +#define _NET_WM_MOVERESIZE_SIZE_TOP 1 +#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 +#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 +#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 +#define _NET_WM_MOVERESIZE_MOVE 8 +#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 +#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 +#define _NET_WM_MOVERESIZE_CANCEL 11 + +static int +query_pressed_buttons (MetaWindow *window) +{ + ClutterModifierType mods; + int button = 0; + + meta_cursor_tracker_get_pointer (window->screen->cursor_tracker, + NULL, NULL, &mods); + + if (mods & CLUTTER_BUTTON1_MASK) + button |= 1 << 1; + if (mods & CLUTTER_BUTTON2_MASK) + button |= 1 << 2; + if (mods & CLUTTER_BUTTON3_MASK) + button |= 1 << 3; + + return button; +} + +gboolean +meta_window_x11_client_message (MetaWindow *window, + XEvent *event) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + MetaDisplay *display; + + display = window->display; + + if (window->override_redirect) + { + /* Don't warn here: we could warn on any of the messages below, + * but we might also receive other client messages that are + * part of protocols we don't know anything about. So, silently + * ignoring is simplest. + */ + return FALSE; + } + + if (event->xclient.message_type == + display->atom__NET_CLOSE_WINDOW) + { + guint32 timestamp; + + if (event->xclient.data.l[0] != 0) + timestamp = event->xclient.data.l[0]; + else + { + meta_warning ("Receiving a NET_CLOSE_WINDOW message for %s without " + "a timestamp! This means some buggy (outdated) " + "application is on the loose!\n", + window->desc); + timestamp = meta_display_get_current_time (window->display); + } + + meta_window_delete (window, timestamp); + + return TRUE; + } + else if (event->xclient.message_type == + display->atom__NET_WM_DESKTOP) + { + int space; + MetaWorkspace *workspace; + + space = event->xclient.data.l[0]; + + meta_verbose ("Request to move %s to workspace %d\n", + window->desc, space); + + workspace = + meta_screen_get_workspace_by_index (window->screen, + space); + + if (workspace) + { + if (window->on_all_workspaces_requested) + meta_window_unstick (window); + meta_window_change_workspace (window, workspace); + } + else if (space == (int) 0xFFFFFFFF) + { + meta_window_stick (window); + } + else + { + meta_verbose ("No such workspace %d for screen\n", space); + } + + meta_verbose ("Window %s now on_all_workspaces = %d\n", + window->desc, window->on_all_workspaces); + + return TRUE; + } + else if (event->xclient.message_type == + display->atom__NET_WM_STATE) + { + gulong action; + Atom first; + Atom second; + + action = event->xclient.data.l[0]; + first = event->xclient.data.l[1]; + second = event->xclient.data.l[2]; + + if (meta_is_verbose ()) + { + char *str1; + char *str2; + + meta_error_trap_push (display); + str1 = XGetAtomName (display->xdisplay, first); + if (meta_error_trap_pop_with_return (display) != Success) + str1 = NULL; + + meta_error_trap_push (display); + str2 = XGetAtomName (display->xdisplay, second); + if (meta_error_trap_pop_with_return (display) != Success) + str2 = NULL; + + meta_verbose ("Request to change _NET_WM_STATE action %lu atom1: %s atom2: %s\n", + action, + str1 ? str1 : "(unknown)", + str2 ? str2 : "(unknown)"); + + meta_XFree (str1); + meta_XFree (str2); + } + + if (first == display->atom__NET_WM_STATE_SHADED || + second == display->atom__NET_WM_STATE_SHADED) + { + gboolean shade; + guint32 timestamp; + + /* Stupid protocol has no timestamp; of course, shading + * sucks anyway so who really cares that we're forced to do + * a roundtrip here? + */ + timestamp = meta_display_get_current_time_roundtrip (window->display); + + shade = (action == _NET_WM_STATE_ADD || + (action == _NET_WM_STATE_TOGGLE && !window->shaded)); + if (shade && window->has_shade_func) + meta_window_shade (window, timestamp); + else + meta_window_unshade (window, timestamp); + } + + if (first == display->atom__NET_WM_STATE_FULLSCREEN || + second == display->atom__NET_WM_STATE_FULLSCREEN) + { + gboolean make_fullscreen; + + make_fullscreen = (action == _NET_WM_STATE_ADD || + (action == _NET_WM_STATE_TOGGLE && !window->fullscreen)); + if (make_fullscreen && window->has_fullscreen_func) + meta_window_make_fullscreen (window); + else + meta_window_unmake_fullscreen (window); + } + + if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || + second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || + first == display->atom__NET_WM_STATE_MAXIMIZED_VERT || + second == display->atom__NET_WM_STATE_MAXIMIZED_VERT) + { + gboolean max; + MetaMaximizeFlags directions = 0; + + max = (action == _NET_WM_STATE_ADD || + (action == _NET_WM_STATE_TOGGLE && + !window->maximized_horizontally)); + + if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || + second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ) + directions |= META_MAXIMIZE_HORIZONTAL; + + if (first == display->atom__NET_WM_STATE_MAXIMIZED_VERT || + second == display->atom__NET_WM_STATE_MAXIMIZED_VERT) + directions |= META_MAXIMIZE_VERTICAL; + + if (max && window->has_maximize_func) + { + if (meta_prefs_get_raise_on_click ()) + meta_window_raise (window); + meta_window_maximize (window, directions); + } + else + { + if (meta_prefs_get_raise_on_click ()) + meta_window_raise (window); + meta_window_unmaximize (window, directions); + } + } + + if (first == display->atom__NET_WM_STATE_MODAL || + second == display->atom__NET_WM_STATE_MODAL) + { + priv->wm_state_modal = + (action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !priv->wm_state_modal); + + meta_window_x11_recalc_window_type (window); + meta_window_queue(window, META_QUEUE_MOVE_RESIZE); + } + + if (first == display->atom__NET_WM_STATE_SKIP_PAGER || + second == display->atom__NET_WM_STATE_SKIP_PAGER) + { + priv->wm_state_skip_pager = + (action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->skip_pager); + + meta_window_recalc_features (window); + meta_window_x11_set_net_wm_state (window); + } + + if (first == display->atom__NET_WM_STATE_SKIP_TASKBAR || + second == display->atom__NET_WM_STATE_SKIP_TASKBAR) + { + priv->wm_state_skip_taskbar = + (action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->skip_taskbar); + + meta_window_recalc_features (window); + meta_window_x11_set_net_wm_state (window); + } + + if (first == display->atom__NET_WM_STATE_ABOVE || + second == display->atom__NET_WM_STATE_ABOVE) + { + if ((action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention)) + meta_window_make_above (window); + else + meta_window_unmake_above (window); + } + + if (first == display->atom__NET_WM_STATE_BELOW || + second == display->atom__NET_WM_STATE_BELOW) + { + window->wm_state_below = + (action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->wm_state_below); + + meta_window_update_layer (window); + meta_window_x11_set_net_wm_state (window); + } + + if (first == display->atom__NET_WM_STATE_DEMANDS_ATTENTION || + second == display->atom__NET_WM_STATE_DEMANDS_ATTENTION) + { + if ((action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention)) + meta_window_set_demands_attention (window); + else + meta_window_unset_demands_attention (window); + } + + if (first == display->atom__NET_WM_STATE_STICKY || + second == display->atom__NET_WM_STATE_STICKY) + { + if ((action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->on_all_workspaces_requested)) + meta_window_stick (window); + else + meta_window_unstick (window); + } + + return TRUE; + } + else if (event->xclient.message_type == + display->atom_WM_CHANGE_STATE) + { + meta_verbose ("WM_CHANGE_STATE client message, state: %ld\n", + event->xclient.data.l[0]); + if (event->xclient.data.l[0] == IconicState && + window->has_minimize_func) + meta_window_minimize (window); + + return TRUE; + } + else if (event->xclient.message_type == + display->atom__NET_WM_MOVERESIZE) + { + int x_root; + int y_root; + int action; + MetaGrabOp op; + int button; + guint32 timestamp; + + /* _NET_WM_MOVERESIZE messages are almost certainly going to come from + * clients when users click on the fake "frame" that the client has, + * thus we should also treat such messages as though it were a + * "frame action". + */ + gboolean const frame_action = TRUE; + + x_root = event->xclient.data.l[0]; + y_root = event->xclient.data.l[1]; + action = event->xclient.data.l[2]; + button = event->xclient.data.l[3]; + + /* FIXME: What a braindead protocol; no timestamp?!? */ + timestamp = meta_display_get_current_time_roundtrip (display); + meta_topic (META_DEBUG_WINDOW_OPS, + "Received _NET_WM_MOVERESIZE message on %s, %d,%d action = %d, button %d\n", + window->desc, + x_root, y_root, action, button); + + op = META_GRAB_OP_NONE; + switch (action) + { + case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: + op = META_GRAB_OP_RESIZING_NW; + break; + case _NET_WM_MOVERESIZE_SIZE_TOP: + op = META_GRAB_OP_RESIZING_N; + break; + case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT: + op = META_GRAB_OP_RESIZING_NE; + break; + case _NET_WM_MOVERESIZE_SIZE_RIGHT: + op = META_GRAB_OP_RESIZING_E; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT: + op = META_GRAB_OP_RESIZING_SE; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOM: + op = META_GRAB_OP_RESIZING_S; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: + op = META_GRAB_OP_RESIZING_SW; + break; + case _NET_WM_MOVERESIZE_SIZE_LEFT: + op = META_GRAB_OP_RESIZING_W; + break; + case _NET_WM_MOVERESIZE_MOVE: + op = META_GRAB_OP_MOVING; + break; + case _NET_WM_MOVERESIZE_SIZE_KEYBOARD: + op = META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN; + break; + case _NET_WM_MOVERESIZE_MOVE_KEYBOARD: + op = META_GRAB_OP_KEYBOARD_MOVING; + break; + case _NET_WM_MOVERESIZE_CANCEL: + /* handled below */ + break; + default: + break; + } + + if (action == _NET_WM_MOVERESIZE_CANCEL) + { + meta_display_end_grab_op (window->display, timestamp); + } + else if (op != META_GRAB_OP_NONE && + ((window->has_move_func && op == META_GRAB_OP_KEYBOARD_MOVING) || + (window->has_resize_func && op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN))) + { + meta_window_begin_grab_op (window, op, frame_action, timestamp); + } + else if (op != META_GRAB_OP_NONE && + ((window->has_move_func && op == META_GRAB_OP_MOVING) || + (window->has_resize_func && + (op != META_GRAB_OP_MOVING && + op != META_GRAB_OP_KEYBOARD_MOVING)))) + { + int button_mask; + + meta_topic (META_DEBUG_WINDOW_OPS, + "Beginning move/resize with button = %d\n", button); + meta_display_begin_grab_op (window->display, + window->screen, + window, + op, + FALSE, + frame_action, + button, 0, + timestamp, + x_root, + y_root); + + button_mask = query_pressed_buttons (window); + + if (button == 0) + { + /* + * the button SHOULD already be included in the message + */ + if ((button_mask & (1 << 1)) != 0) + button = 1; + else if ((button_mask & (1 << 2)) != 0) + button = 2; + else if ((button_mask & (1 << 3)) != 0) + button = 3; + + if (button != 0) + window->display->grab_button = button; + else + meta_display_end_grab_op (window->display, + timestamp); + } + else + { + /* There is a potential race here. If the user presses and + * releases their mouse button very fast, it's possible for + * both the ButtonPress and ButtonRelease to be sent to the + * client before it can get a chance to send _NET_WM_MOVERESIZE + * to us. When that happens, we'll become stuck in a grab + * state, as we haven't received a ButtonRelease to cancel the + * grab. + * + * We can solve this by querying after we take the explicit + * pointer grab -- if the button isn't pressed, we cancel the + * drag immediately. + */ + + if ((button_mask & (1 << button)) == 0) + meta_display_end_grab_op (window->display, timestamp); + } + } + + return TRUE; + } + else if (event->xclient.message_type == + display->atom__NET_MOVERESIZE_WINDOW) + { + int gravity; + guint value_mask; + + gravity = (event->xclient.data.l[0] & 0xff); + value_mask = (event->xclient.data.l[0] & 0xf00) >> 8; + /* source = (event->xclient.data.l[0] & 0xf000) >> 12; */ + + if (gravity == 0) + gravity = window->size_hints.win_gravity; + + meta_window_move_resize_request(window, + value_mask, + gravity, + event->xclient.data.l[1], /* x */ + event->xclient.data.l[2], /* y */ + event->xclient.data.l[3], /* width */ + event->xclient.data.l[4]); /* height */ + } + else if (event->xclient.message_type == + display->atom__NET_ACTIVE_WINDOW) + { + MetaClientType source_indication; + guint32 timestamp; + + meta_verbose ("_NET_ACTIVE_WINDOW request for window '%s', activating\n", + window->desc); + + source_indication = event->xclient.data.l[0]; + timestamp = event->xclient.data.l[1]; + + if (source_indication > META_CLIENT_TYPE_MAX_RECOGNIZED) + source_indication = META_CLIENT_TYPE_UNKNOWN; + + if (timestamp == 0) + { + /* Client using older EWMH _NET_ACTIVE_WINDOW without a timestamp */ + meta_warning ("Buggy client sent a _NET_ACTIVE_WINDOW message with a " + "timestamp of 0 for %s\n", + window->desc); + timestamp = meta_display_get_current_time (display); + } + + meta_window_activate_full (window, timestamp, source_indication, NULL); + return TRUE; + } + else if (event->xclient.message_type == + display->atom__NET_WM_FULLSCREEN_MONITORS) + { + gulong top, bottom, left, right; + + meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n", + window->desc); + + top = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[0]); + bottom = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[1]); + left = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[2]); + right = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[3]); + /* source_indication = event->xclient.data.l[4]; */ + + meta_window_update_fullscreen_monitors (window, top, bottom, left, right); + } + + return FALSE; +} + +static void +set_wm_state_on_xwindow (MetaDisplay *display, + Window xwindow, + int state) +{ + unsigned long data[2]; + + /* Mutter doesn't use icon windows, so data[1] should be None + * according to the ICCCM 2.0 Section 4.1.3.1. + */ + data[0] = state; + data[1] = None; + + meta_error_trap_push (display); + XChangeProperty (display->xdisplay, xwindow, + display->atom_WM_STATE, + display->atom_WM_STATE, + 32, PropModeReplace, (guchar*) data, 2); + meta_error_trap_pop (display); +} + +void +meta_window_x11_set_wm_state (MetaWindow *window) +{ + int state; + + if (window->withdrawn) + state = WithdrawnState; + else if (window->iconic) + state = IconicState; + else + state = NormalState; + + set_wm_state_on_xwindow (window->display, window->xwindow, state); +} + +/* The MUTTER_WM_CLASS_FILTER environment variable is designed for + * performance and regression testing environments where we want to do + * tests with only a limited set of windows and ignore all other windows + * + * When it is set to a comma separated list of WM_CLASS class names, all + * windows not matching the list will be ignored. + * + * Returns TRUE if window has been filtered out and should be ignored. + */ +static gboolean +maybe_filter_xwindow (MetaDisplay *display, + Window xwindow, + gboolean must_be_viewable, + XWindowAttributes *attrs) +{ + static char **filter_wm_classes = NULL; + static gboolean initialized = FALSE; + XClassHint class_hint; + gboolean filtered; + Status success; + int i; + + if (!initialized) + { + const char *filter_string = g_getenv ("MUTTER_WM_CLASS_FILTER"); + if (filter_string) + filter_wm_classes = g_strsplit (filter_string, ",", -1); + initialized = TRUE; + } + + if (!filter_wm_classes || !filter_wm_classes[0]) + return FALSE; + + filtered = TRUE; + + meta_error_trap_push (display); + success = XGetClassHint (display->xdisplay, xwindow, &class_hint); + + if (success) + { + for (i = 0; filter_wm_classes[i]; i++) + { + if (strcmp (class_hint.res_class, filter_wm_classes[i]) == 0) + { + filtered = FALSE; + break; + } + } + + XFree (class_hint.res_name); + XFree (class_hint.res_class); + } + + if (filtered) + { + /* We want to try and get the window managed by the next WM that come along, + * so we need to make sure that windows that are requested to be mapped while + * Mutter is running (!must_be_viewable), or windows already viewable at startup + * get a non-withdrawn WM_STATE property. Previously unmapped windows are left + * with whatever WM_STATE property they had. + */ + if (!must_be_viewable || attrs->map_state == IsViewable) + { + gulong old_state; + + if (!meta_prop_get_cardinal_with_atom_type (display, xwindow, + display->atom_WM_STATE, + display->atom_WM_STATE, + &old_state)) + old_state = WithdrawnState; + + if (old_state == WithdrawnState) + set_wm_state_on_xwindow (display, xwindow, NormalState); + } + + /* Make sure filtered windows are hidden from view */ + XUnmapWindow (display->xdisplay, xwindow); + } + + meta_error_trap_pop (display); + + return filtered; +} + +static gboolean +is_our_xwindow (MetaDisplay *display, + MetaScreen *screen, + Window xwindow, + XWindowAttributes *attrs) +{ + if (xwindow == screen->no_focus_window) + return TRUE; + + if (xwindow == screen->wm_sn_selection_window) + return TRUE; + + if (xwindow == screen->wm_cm_selection_window) + return TRUE; + + if (xwindow == screen->guard_window) + return TRUE; + + if (xwindow == XCompositeGetOverlayWindow (display->xdisplay, screen->xroot)) + return TRUE; + + /* Any windows created via meta_create_offscreen_window */ + if (attrs->override_redirect && attrs->x == -100 && attrs->y == -100 && attrs->width == 1 && attrs->height == 1) + return TRUE; + + return FALSE; +} + +#ifdef WITH_VERBOSE_MODE +static const char* +wm_state_to_string (int state) +{ + switch (state) + { + case NormalState: + return "NormalState"; + case IconicState: + return "IconicState"; + case WithdrawnState: + return "WithdrawnState"; + } + + return "Unknown"; +} +#endif + +MetaWindow * +meta_window_x11_new (MetaDisplay *display, + Window xwindow, + gboolean must_be_viewable, + MetaCompEffect effect) +{ + MetaScreen *screen = display->screen; + XWindowAttributes attrs; + gulong existing_wm_state; + MetaWindow *window = NULL; + gulong event_mask; + + meta_verbose ("Attempting to manage 0x%lx\n", xwindow); + + if (meta_display_xwindow_is_a_no_focus_window (display, xwindow)) + { + meta_verbose ("Not managing no_focus_window 0x%lx\n", + xwindow); + return NULL; + } + + meta_error_trap_push (display); /* Push a trap over all of window + * creation, to reduce XSync() calls + */ + /* + * This function executes without any server grabs held. This means that + * the window could have already gone away, or could go away at any point, + * so we must be careful with X error handling. + */ + + if (!XGetWindowAttributes (display->xdisplay, xwindow, &attrs)) + { + meta_verbose ("Failed to get attributes for window 0x%lx\n", + xwindow); + goto error; + } + + if (attrs.root != screen->xroot) + { + meta_verbose ("Not on our screen\n"); + goto error; + } + + if (is_our_xwindow (display, screen, xwindow, &attrs)) + { + meta_verbose ("Not managing our own windows\n"); + goto error; + } + + if (maybe_filter_xwindow (display, xwindow, must_be_viewable, &attrs)) + { + meta_verbose ("Not managing filtered window\n"); + goto error; + } + + existing_wm_state = WithdrawnState; + if (must_be_viewable && attrs.map_state != IsViewable) + { + /* Only manage if WM_STATE is IconicState or NormalState */ + gulong state; + + /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */ + if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow, + display->atom_WM_STATE, + display->atom_WM_STATE, + &state) && + (state == IconicState || state == NormalState))) + { + meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow); + goto error; + } + + existing_wm_state = state; + meta_verbose ("WM_STATE of %lx = %s\n", xwindow, + wm_state_to_string (existing_wm_state)); + } + + meta_error_trap_push (display); + + /* + * XAddToSaveSet can only be called on windows created by a different + * client. with Mutter we want to be able to create manageable windows + * from within the process (such as a dummy desktop window). As we do not + * want this call failing to prevent the window from being managed, we + * call this before creating the return-checked error trap. + */ + XAddToSaveSet (display->xdisplay, xwindow); + + meta_error_trap_push (display); + + event_mask = PropertyChangeMask; + if (attrs.override_redirect) + event_mask |= StructureNotifyMask; + + /* If the window is from this client (a menu, say) we need to augment + * the event mask, not replace it. For windows from other clients, + * attrs.your_event_mask will be empty at this point. + */ + XSelectInput (display->xdisplay, xwindow, attrs.your_event_mask | event_mask); + + { + unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; + XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; + + meta_core_add_old_event_mask (display->xdisplay, xwindow, &mask); + + XISetMask (mask.mask, XI_Enter); + XISetMask (mask.mask, XI_Leave); + XISetMask (mask.mask, XI_FocusIn); + XISetMask (mask.mask, XI_FocusOut); + + XISelectEvents (display->xdisplay, xwindow, &mask, 1); + } + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (display)) + XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask); +#endif + + /* Get rid of any borders */ + if (attrs.border_width != 0) + XSetWindowBorderWidth (display->xdisplay, xwindow, 0); + + /* Get rid of weird gravities */ + if (attrs.win_gravity != NorthWestGravity) + { + XSetWindowAttributes set_attrs; + + set_attrs.win_gravity = NorthWestGravity; + + XChangeWindowAttributes (display->xdisplay, + xwindow, + CWWinGravity, + &set_attrs); + } + + if (meta_error_trap_pop_with_return (display) != Success) + { + meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n", + xwindow); + goto error; + } + + window = _meta_window_shared_new (display, + screen, + META_WINDOW_CLIENT_TYPE_X11, + NULL, + xwindow, + existing_wm_state, + effect, + &attrs); + meta_window_set_surface_mapped (window, TRUE); + + meta_error_trap_pop (display); /* pop the XSync()-reducing trap */ + return window; + +error: + meta_error_trap_pop (display); + return NULL; +} + +void +meta_window_x11_recalc_window_type (MetaWindow *window) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + MetaWindowType type; + + if (priv->type_atom != None) + { + if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP) + type = META_WINDOW_DESKTOP; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK) + type = META_WINDOW_DOCK; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR) + type = META_WINDOW_TOOLBAR; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU) + type = META_WINDOW_MENU; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY) + type = META_WINDOW_UTILITY; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH) + type = META_WINDOW_SPLASHSCREEN; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG) + type = META_WINDOW_DIALOG; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL) + type = META_WINDOW_NORMAL; + /* The below are *typically* override-redirect windows, but the spec does + * not disallow using them for managed windows. + */ + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU) + type = META_WINDOW_DROPDOWN_MENU; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU) + type = META_WINDOW_POPUP_MENU; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP) + type = META_WINDOW_TOOLTIP; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION) + type = META_WINDOW_NOTIFICATION; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_COMBO) + type = META_WINDOW_COMBO; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DND) + type = META_WINDOW_DND; + else + { + char *atom_name; + + /* + * Fallback on a normal type, and print warning. Don't abort. + */ + type = META_WINDOW_NORMAL; + + meta_error_trap_push (window->display); + atom_name = XGetAtomName (window->display->xdisplay, + priv->type_atom); + meta_error_trap_pop (window->display); + + meta_warning ("Unrecognized type atom [%s] set for %s \n", + atom_name ? atom_name : "unknown", + window->desc); + + if (atom_name) + XFree (atom_name); + } + } + else if (window->transient_for != NULL) + { + type = META_WINDOW_DIALOG; + } + else + { + type = META_WINDOW_NORMAL; + } + + if (type == META_WINDOW_DIALOG && priv->wm_state_modal) + type = META_WINDOW_MODAL_DIALOG; + + /* We don't want to allow override-redirect windows to have decorated-window + * types since that's just confusing. + */ + if (window->override_redirect) + { + switch (window->type) + { + /* Decorated types */ + case META_WINDOW_NORMAL: + case META_WINDOW_DIALOG: + case META_WINDOW_MODAL_DIALOG: + case META_WINDOW_MENU: + case META_WINDOW_UTILITY: + type = META_WINDOW_OVERRIDE_OTHER; + break; + /* Undecorated types, normally not override-redirect */ + case META_WINDOW_DESKTOP: + case META_WINDOW_DOCK: + case META_WINDOW_TOOLBAR: + case META_WINDOW_SPLASHSCREEN: + /* Undecorated types, normally override-redirect types */ + case META_WINDOW_DROPDOWN_MENU: + case META_WINDOW_POPUP_MENU: + case META_WINDOW_TOOLTIP: + case META_WINDOW_NOTIFICATION: + case META_WINDOW_COMBO: + case META_WINDOW_DND: + /* To complete enum */ + case META_WINDOW_OVERRIDE_OTHER: + break; + } + } + + meta_verbose ("Calculated type %u for %s, old type %u\n", + type, window->desc, type); + meta_window_set_type (window, type); +} + +/** + * meta_window_x11_configure_notify: (skip) + * @window: a #MetaWindow + * @event: a #XConfigureEvent + * + * This is used to notify us of an unrequested configuration + * (only applicable to override redirect windows) + */ +void +meta_window_x11_configure_notify (MetaWindow *window, + XConfigureEvent *event) +{ + g_assert (window->override_redirect); + g_assert (window->frame == NULL); + + window->rect.x = event->x; + window->rect.y = event->y; + window->rect.width = event->width; + window->rect.height = event->height; + meta_window_update_monitor (window); + + /* Whether an override-redirect window is considered fullscreen depends + * on its geometry. + */ + if (window->override_redirect) + meta_screen_queue_check_fullscreen (window->screen); + + if (!event->override_redirect && !event->send_event) + meta_warning ("Unhandled change of windows override redirect status\n"); + + meta_compositor_sync_window_geometry (window->display->compositor, window, FALSE); +} diff --git a/src/x11/window-x11.h b/src/x11/window-x11.h new file mode 100644 index 0000000..29d95b0 --- /dev/null +++ b/src/x11/window-x11.h @@ -0,0 +1,64 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2002 Red Hat, Inc. + * Copyright (C) 2003, 2004 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef META_WINDOW_X11_H +#define META_WINDOW_X11_H + +#include <meta/window.h> +#include <X11/Xlib.h> + +G_BEGIN_DECLS + +#define META_TYPE_WINDOW_X11 (meta_window_x11_get_type()) +#define META_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW_X11, MetaWindowX11)) +#define META_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW_X11, MetaWindowX11Class)) +#define META_IS_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW_X11)) +#define META_IS_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW_X11)) +#define META_WINDOW_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW_X11, MetaWindowX11Class)) + +GType meta_window_x11_get_type (void); + +typedef struct _MetaWindowX11 MetaWindowX11; +typedef struct _MetaWindowX11Class MetaWindowX11Class; + +void meta_window_x11_set_net_wm_state (MetaWindow *window); +void meta_window_x11_set_wm_state (MetaWindow *window); + +void meta_window_x11_update_role (MetaWindow *window); +void meta_window_x11_update_net_wm_type (MetaWindow *window); +void meta_window_x11_update_opaque_region (MetaWindow *window); +void meta_window_x11_update_input_region (MetaWindow *window); +void meta_window_x11_update_shape_region (MetaWindow *window); + +void meta_window_x11_recalc_window_type (MetaWindow *window); + +gboolean meta_window_x11_configure_request (MetaWindow *window, + XEvent *event); +gboolean meta_window_x11_property_notify (MetaWindow *window, + XEvent *event); +gboolean meta_window_x11_client_message (MetaWindow *window, + XEvent *event); + +void meta_window_x11_configure_notify (MetaWindow *window, + XConfigureEvent *event); + +#endif diff --git a/src/core/xprops.c b/src/x11/xprops.c index 5c96319..44c1113 100644 --- a/src/core/xprops.c +++ b/src/x11/xprops.c @@ -150,7 +150,7 @@ validate_or_free_results (GetPropertyResults *results, if (res_name == NULL) res_name = "unknown"; - meta_warning (_("Window 0x%lx has property %s\nthat was expected to have type %s format %d\nand actually has type %s format %d n_items %d.\nThis is most likely an application bug, not a window manager bug.\nThe window has title=\"%s\" class=\"%s\" name=\"%s\"\n"), + meta_warning ("Window 0x%lx has property %s\nthat was expected to have type %s format %d\nand actually has type %s format %d n_items %d.\nThis is most likely an application bug, not a window manager bug.\nThe window has title=\"%s\" class=\"%s\" name=\"%s\"\n", results->xwindow, prop_name ? prop_name : "(bad atom)", expected_name ? expected_name : "(bad atom)", @@ -191,7 +191,7 @@ get_property (MetaDisplay *display, results->bytes_after = 0; results->format = 0; - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); if (XGetWindowProperty (display->xdisplay, xwindow, xatom, 0, G_MAXLONG, False, req_type, &results->type, &results->format, @@ -406,7 +406,7 @@ utf8_string_from_results (GetPropertyResults *results, char *name; name = XGetAtomName (results->display->xdisplay, results->xatom); - meta_warning (_("Property %s on window 0x%lx contained invalid UTF-8\n"), + meta_warning ("Property %s on window 0x%lx contained invalid UTF-8\n", name, results->xwindow); meta_XFree (name); XFree (results->prop); @@ -489,7 +489,7 @@ utf8_list_from_results (GetPropertyResults *results, meta_error_trap_push (results->display); name = XGetAtomName (results->display->xdisplay, results->xatom); meta_error_trap_pop (results->display); - meta_warning (_("Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n"), + meta_warning ("Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n", name, results->xwindow, i); meta_XFree (name); meta_XFree (results->prop); @@ -534,6 +534,81 @@ meta_prop_get_utf8_list (MetaDisplay *display, return utf8_list_from_results (&results, str_p, n_str_p); } +/* this one freakishly returns g_malloc memory */ +static gboolean +latin1_list_from_results (GetPropertyResults *results, + char ***str_p, + int *n_str_p) +{ + int i; + int n_strings; + char **retval; + const char *p; + + *str_p = NULL; + *n_str_p = 0; + + if (!validate_or_free_results (results, 8, XA_STRING, FALSE)) + return FALSE; + + /* I'm not sure this is right, but I'm guessing the + * property is nul-separated + */ + i = 0; + n_strings = 0; + while (i < (int) results->n_items) + { + if (results->prop[i] == '\0') + ++n_strings; + ++i; + } + + if (results->prop[results->n_items - 1] != '\0') + ++n_strings; + + /* we're guaranteed that results->prop has a nul on the end + * by XGetWindowProperty + */ + + retval = g_new0 (char*, n_strings + 1); + + p = (char *)results->prop; + i = 0; + while (i < n_strings) + { + retval[i] = g_strdup (p); + + p = p + strlen (p) + 1; + ++i; + } + + *str_p = retval; + *n_str_p = i; + + meta_XFree (results->prop); + results->prop = NULL; + + return TRUE; +} + +gboolean +meta_prop_get_latin1_list (MetaDisplay *display, + Window xwindow, + Atom xatom, + char ***str_p, + int *n_str_p) +{ + GetPropertyResults results; + + *str_p = NULL; + + if (!get_property (display, xwindow, xatom, + XA_STRING, &results)) + return FALSE; + + return latin1_list_from_results (&results, str_p, n_str_p); +} + void meta_prop_set_utf8_string_hint (MetaDisplay *display, Window xwindow, @@ -661,6 +736,29 @@ meta_prop_get_cardinal_with_atom_type (MetaDisplay *display, return cardinal_with_atom_type_from_results (&results, prop_type, cardinal_p); } +static char * +text_property_to_utf8 (Display *xdisplay, + const XTextProperty *prop) +{ + char *ret = NULL; + char **local_list = NULL; + int count = 0; + int res; + + res = XmbTextPropertyToTextList (xdisplay, prop, &local_list, &count); + if (res == XNoMemory || res == XLocaleNotSupported || res == XConverterNotFound) + goto out; + + if (count == 0) + goto out; + + ret = g_strdup (local_list[0]); + + out: + meta_XFree (local_list); + return ret; +} + static gboolean text_property_from_results (GetPropertyResults *results, char **utf8_str_p) @@ -668,15 +766,14 @@ text_property_from_results (GetPropertyResults *results, XTextProperty tp; *utf8_str_p = NULL; - + tp.value = results->prop; results->prop = NULL; tp.encoding = results->type; tp.format = results->format; tp.nitems = results->n_items; - *utf8_str_p = meta_text_property_to_utf8 (results->display->xdisplay, - &tp); + *utf8_str_p = text_property_to_utf8 (results->display->xdisplay, &tp); if (tp.value != NULL) XFree (tp.value); diff --git a/src/core/xprops.h b/src/x11/xprops.h index cad7a1f..241557f 100644 --- a/src/core/xprops.h +++ b/src/x11/xprops.h @@ -100,6 +100,11 @@ gboolean meta_prop_get_utf8_list (MetaDisplay *display, Atom xatom, char ***str_p, int *n_str_p); +gboolean meta_prop_get_latin1_list (MetaDisplay *display, + Window xwindow, + Atom xatom, + char ***str_p, + int *n_str_p); void meta_prop_set_utf8_string_hint (MetaDisplay *display, Window xwindow, diff --git a/stamp.h.in b/stamp.h.in deleted file mode 100644 index e69de29..0000000 --- a/stamp.h.in +++ /dev/null diff --git a/test/tokentest/Makefile b/test/tokentest/Makefile deleted file mode 100644 index 010fd60..0000000 --- a/test/tokentest/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# completely hacked-up makefile, proceed at your own risk, etc - -default: - @echo "Try 'make tp' or 'make glib'" - -tp: tokentest.c - gcc `pkg-config --cflags --libs glib-2.0 gdk-2.0 atk` -DMUTTER_DATADIR=\"/usr/share/mutter\" -I../.. -I../../src -I../../src/include tokentest.c ../../src/ui/theme.c ../../src/ui/gradient.c -o tp diff --git a/test/tokentest/README b/test/tokentest/README deleted file mode 100644 index c98dbe4..0000000 --- a/test/tokentest/README +++ /dev/null @@ -1,19 +0,0 @@ -Tokeniser test -============== -This directory contains a set of tools for checking the behaviour -of the tokeniser for Metacity theme files. - -tokentest.ini contains a list of all expressions retrieved from -all theme files on art.gnome.org, and mappings to what the tokenising -should be, in a separate representation. get-tokens.py produces the -template version of this; it will produce a file with no expected -values. - -tokentest.c will either check that a tokeniser behaves according to -tokentest.ini, or, if it finds a file, is empty it will print the -values that the tokeniser it's using is producing. - -The makefile is a hacky attempt at letting you compile either against -Metacity's existing tokeniser or one which uses GLib's "scanner". - -This code may or may not eventually end up in the automated test suite.
\ No newline at end of file diff --git a/test/tokentest/get-tokens.py b/test/tokentest/get-tokens.py deleted file mode 100644 index 42a8844..0000000 --- a/test/tokentest/get-tokens.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/python -# Copyright (C) 2008 Thomas Thurman -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see <http://www.gnu.org/licenses/>. - - -import os -import xml.sax - -standard = ['x', 'y', 'width', 'height'] - -expressions = { - 'line': ['x1', 'x2', 'y1', 'y2'], - 'rectangle': standard, - 'arc': standard, - 'clip': standard, - 'gradient': standard, - 'image': standard, - 'gtk_arrow': standard, - 'gtk_box': standard, - 'gtk_vline': standard, - 'icon': standard, - 'title': standard, - 'include': standard, - 'tile': ['x', 'y', 'width', 'height', - 'tile_xoffset', 'tile_yoffset', - 'tile_width', 'tile_height'], -} - -all_themes = '../../../all-themes/' - -result = {} - -class themeparser: - def __init__(self, name): - self.filename = name - - def processingInstruction(self): - pass - - def characters(self, what): - pass - - def setDocumentLocator(self, where): - pass - - def startDocument(self): - pass - - def startElement(self, name, attrs): - if expressions.has_key(name): - for attr in expressions[name]: - if attrs.has_key(attr): - expression = attrs[attr] - if not result.has_key(expression): result[expression] = {} - result[expression][self.filename] = 1 - - def endElement(self, name): - pass # print "end element" - - def endDocument(self): - pass - -def maybe_parse(themename, filename): - if os.access(all_themes+filename, os.F_OK): - parser = themeparser(themename) - xml.sax.parse(all_themes+filename, parser) - -for theme in os.listdir(all_themes): - maybe_parse(theme, theme+'/metacity-1/metacity-theme-1.xml') - maybe_parse(theme, theme+'/metacity-theme-1.xml') - -print '[tokentest0]' - -for expr in sorted(result.keys()): - print "# %s" % (', '.join(sorted(result[expr]))) - print "%s=REQ" % (expr) - print diff --git a/test/tokentest/tokentest.c b/test/tokentest/tokentest.c deleted file mode 100644 index 107d9ee..0000000 --- a/test/tokentest/tokentest.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * tokentest.c - test for Metacity's tokeniser - * - * Copyright (C) 2008 Thomas Thurman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/* Still under heavy development. */ -/* Especially: FIXME: GErrors need checking! */ - -#include <stdio.h> -#include <glib/gerror.h> -#include <gtk/gtkobject.h> -#include <gtk/gtkicontheme.h> -#include <ui/theme.h> -#include <util.h> - -#define TOKENTEST_GROUP "tokentest0" - -/************************/ -/* Dummy functions which are just here to keep the linker happy */ - -MetaTheme* meta_theme_load (const char *theme_name, - GError **err) { - /* dummy */ - return NULL; -} - -void -meta_bug(const char *format, ...) -{ - /* dummy */ -} - -void -meta_warning(const char *format, ...) -{ - /* dummy */ -} - -GType -gtk_widget_get_type (void) -{ - /* dummy */ -} - -GType -gtk_object_get_type (void) -{ - /* dummy */ -} - -void gtk_paint_arrow (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - GtkArrowType arrow_type, - gboolean fill, - gint x, - gint y, - gint width, - gint height) -{ - /* dummy */ -} - -void gtk_paint_vline (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint y1_, - gint y2_, - gint x) -{ - /* dummy */ -} -void gtk_paint_box (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x, - gint y, - gint width, - gint height) -{ - /* dummy */ -} - -GtkIconTheme *gtk_icon_theme_get_default (void) -{ - /* dummy */ -} - -GdkPixbuf * gtk_icon_theme_load_icon (GtkIconTheme *icon_theme, - const gchar *icon_name, - gint size, - GtkIconLookupFlags flags, - GError **error) -{ - /* dummy */ -} - -MetaRectangle meta_rect (int x, int y, int width, int height) -{ - /* dummy */ -} - -void -meta_topic_real (MetaDebugTopic topic, - const char *format, - ...) -{ - /* dummy */ -} - - -/*********************************/ - -GString *draw_spec_to_string(MetaDrawSpec *spec) -{ - GString *result; - int i; - - if (spec == NULL) - return g_string_new ("NONE"); - - result = g_string_new (""); - - if (spec->constant) - { - g_string_append_printf (result, "{%d==}", spec->value); - } - - for (i=0; i<spec->n_tokens; i++) - { - PosToken t = spec->tokens[i]; - - switch (t.type) - { - case POS_TOKEN_INT: - g_string_append_printf (result, "(int %d)", t.d.i.val); - break; - - case POS_TOKEN_DOUBLE: - g_string_append_printf (result, "(double %g)", t.d.d.val); - break; - - case POS_TOKEN_OPERATOR: - - switch (t.d.o.op) { - case POS_OP_NONE: - g_string_append (result, "(no-op)"); - break; - - case POS_OP_ADD: - g_string_append (result, "(add)"); - break; - - case POS_OP_SUBTRACT: - g_string_append (result, "(subtract)"); - break; - - case POS_OP_MULTIPLY: - g_string_append (result, "(multiply)"); - break; - - case POS_OP_DIVIDE: - g_string_append (result, "(divide)"); - break; - - case POS_OP_MOD: - g_string_append (result, "(mod)"); - break; - - case POS_OP_MAX: - g_string_append (result, "(max)"); - break; - - case POS_OP_MIN: - g_string_append (result, "(min)"); - break; - - default: - g_string_append_printf (result, "(op %d)", t.d.o.op); - } - - break; - - case POS_TOKEN_VARIABLE: - g_string_append_printf (result, "(str %s)", t.d.v.name); - break; - - case POS_TOKEN_OPEN_PAREN: - g_string_append (result, "( "); - break; - - case POS_TOKEN_CLOSE_PAREN: - g_string_append (result, " )"); - break; - - default: - g_string_append_printf (result, "(strange %d)", t.type); - } - - } - - return result; -} - -GKeyFile *keys; - -void -load_keys () -{ - GError* err = NULL; - gchar** keys_of_file; - gchar** cursor; - gboolean ever_printed_header = FALSE; - gint passes = 0, fails = 0; - - keys = g_key_file_new (); - - g_key_file_load_from_file (keys, - "tokentest.ini", - G_KEY_FILE_KEEP_COMMENTS, - &err); - - keys_of_file = g_key_file_get_keys (keys, - TOKENTEST_GROUP, - NULL, - &err); - - cursor = keys_of_file; - - while (*cursor) - { - gchar *desideratum = g_key_file_get_value (keys, - TOKENTEST_GROUP, - *cursor, - &err); - MetaTheme *dummy = meta_theme_new (); - MetaDrawSpec *spec; - GString *str; - - spec = meta_draw_spec_new (dummy, *cursor, &err); - - str = draw_spec_to_string (spec); - - if (strcmp ("REQ", desideratum)==0) { - gchar *comment = g_key_file_get_comment (keys, TOKENTEST_GROUP, *cursor, &err); - - if (!ever_printed_header) { - g_print ("[%s]\n", TOKENTEST_GROUP); - ever_printed_header = TRUE; - } - - g_print ("\n#%s%s=%s\n", comment? comment: "", *cursor, str->str); - g_free (comment); - } else if (strcmp (str->str, desideratum)==0) { - g_print("PASS: %s\n", *cursor); - passes++; - } else { - g_warning ("FAIL: %s, wanted %s, got %s\n", - *cursor, desideratum, str->str); - fails++; - } - - meta_theme_free (dummy); - g_string_free (str, TRUE); - g_free (desideratum); - - cursor++; - } - - g_strfreev (keys_of_file); - - g_print("\n# Passes: %d. Fails: %d.\n", passes, fails); -} - -int -main () -{ - load_keys (); -} diff --git a/test/tokentest/tokentest.ini b/test/tokentest/tokentest.ini deleted file mode 100644 index edfc587..0000000 --- a/test/tokentest/tokentest.ini +++ /dev/null @@ -1,1873 +0,0 @@ -# Copyright (C) 2008 Thomas Thurman and others -# Generated using the "get-tokens.py" script from all themes on -# art.gnome.org, which are all released under DFSG-compatible -# licences. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see <http://www.gnu.org/licenses/>. - -########################### - -[tokentest0] - -########################### - -# Some very simple examples -width+height=(str width)(add)(str height) -width*height=(str width)(multiply)(str height) -width `min` height=(str width)(min)(str height) - -########################### - -# Strings which can't possibly be well-formed -~~~=NONE - -########################### - -# Strings auto-generated by the original tokeniser -# from art.gnome.org themes (the theme name is given -# in a comment) - -# Amiga, AmigaRelief, pOS -(((height - title_height) / 2) `max` 0)=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) ) - -# Amiga, AmigaRelief, pOS -(((height - title_height) / 2) `max` 0)=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) ) - -# Aquarius, Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Gilouche, GiloucheIM, River, SmoothGNOME, TangoDance, c2 -(((height - title_height) / 2) `max` 0) + 1=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) )(add)(int 1) - -# Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, River, SmoothGNOME, TangoDance, c2 -(((height - title_height) / 2) `max` 0) + 2=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) )(add)(int 2) - -# Clearlooks-RedExit -(((height - title_height) / 2) `max` 0) - 1=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) )(subtract)(int 1) - -# Gilouche, GiloucheIM -(((height - title_height) / 2) `max` 0)-1=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) )(subtract)(int 1) - -# Gilouche, GiloucheIM -((3 `max` (width-title_width)) / 2)=( ( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2) ) - -# Gilouche, GiloucheIM -((3 `max` (width-title_width)) / 2)+1=( ( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2) )(add)(int 1) - -# Gilouche, GiloucheIM -((3 `max` (width-title_width)) / 2)-1=( ( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2) )(subtract)(int 1) - -# Esco -((height - (ButtonIPad + 1) * 2) * 0.4) * 0.67=( ( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.4) )(multiply)(double 0.67) - -# Atlanta, Bright, Carved2, Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, Gilouche, GiloucheIM, Metabox, Mista, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, River, Sandwish, Simple, SmoothGNOME, TangoDance, Tetelestai-Modern -((height - title_height) / 2) `max` 0=( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) - -# Simple, Tetelestai-Modern -((height - title_height) / 2) `max` 0 + 1=( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0)(add)(int 1) - -# Outcrop -((height - title_height) / 2) `max` 0 +2=( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0)(add)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((height-(Bmin`max`height-Bpad*2))/2)=( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((height-(Bmin`max`height-Bpad*2))/2) + 1=( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(add)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((height-(Bmin`max`height-Bpad*2))/2) + 2=( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(add)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((height-(Bmin`max`height-Bpad*2))/2) - 1=( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 1) - -# Clearbox-in, Clearbox-out, Simplebox -((height-title_height)/2) `max` 0=( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) - -# Crux -((left_width + ButtonWidth + IconTitleSpacing + title_width + CenterTitlePieceWidth * height / 22) `min` (width - 3 * ButtonWidth - right_width)) + 1=( ( (str left_width)(add)(str ButtonWidth)(add)(str IconTitleSpacing)(add)(str title_width)(add)(str CenterTitlePieceWidth)(multiply)(str height)(divide)(int 22) )(min)( (str width)(subtract)(int 3)(multiply)(str ButtonWidth)(subtract)(str right_width) ) )(add)(int 1) - -# Crux -((left_width + ButtonWidth + IconTitleSpacing + title_width) `min` (width - object_width * height / 22 - right_width - 3 * ButtonWidth)) + 1=( ( (str left_width)(add)(str ButtonWidth)(add)(str IconTitleSpacing)(add)(str title_width) )(min)( (str width)(subtract)(str object_width)(multiply)(str height)(divide)(int 22)(subtract)(str right_width)(subtract)(int 3)(multiply)(str ButtonWidth) ) )(add)(int 1) - -# Crux, Sandwish -((title_width + height / 2 + 32)) + 1=( ( (str title_width)(add)(str height)(divide)(int 2)(add)(int 32) ) )(add)(int 1) - -# Crux, Sandwish -((title_width + height / 2 - 4) `min` (width - object_width - 26))=( ( (str title_width)(add)(str height)(divide)(int 2)(subtract)(int 4) )(min)( (str width)(subtract)(str object_width)(subtract)(int 26) ) ) - -# Crux, Sandwish -((title_width + height / 2) `min` (width - object_width - 6)) + 1=( ( (str title_width)(add)(str height)(divide)(int 2) )(min)( (str width)(subtract)(str object_width)(subtract)(int 6) ) )(add)(int 1) - -# Sandwish -((title_width - 4) `min` (title_width/2-10))=( ( (str title_width)(subtract)(int 4) )(min)( (str title_width)(divide)(int 2)(subtract)(int 10) ) ) - -# Sandwish -((title_width) `min` (title_width/2-10))=( ( (str title_width) )(min)( (str title_width)(divide)(int 2)(subtract)(int 10) ) ) - -# Sandwish -((title_width) `min` (width)) + 1=( ( (str title_width) )(min)( (str width) ) )(add)(int 1) - -# Sandwish -((title_width)) + 1=( ( (str title_width) ) )(add)(int 1) - -# Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2 -((width - title_width) / 2)=( ( (str width)(subtract)(str title_width) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((width-(Bmin`max`height-Bpad*2))/2)=( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((width-(Bmin`max`height-Bpad*2))/2) + 1=( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(add)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((width-(Bmin`max`height-Bpad*2))/2) + 2=( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(add)(int 2) - -# Sloth -((width-title_width)/2) `max` 40=( ( (str width)(subtract)(str title_width) )(divide)(int 2) )(max)(int 40) - -# Atlanta, EasyListening, Metabox, Outcrop -(0 `max` (width-title_width)) / 2=( (int 0)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2) - -# Outcrop -(0 `max` (width-title_width)) / 2 +1=( (int 0)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2)(add)(int 1) - -# EasyListening -(0 `max` (width-title_width)) / 2 - 1=( (int 0)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2)(subtract)(int 1) - -# Atlanta, Bright, Metabox, Outcrop -(0 `max` (width-title_width-mini_icon_width-IconTitleSpacing)) / 2=( (int 0)(max)( (str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing) ) )(divide)(int 2) - -# Atlanta, Metabox, Outcrop, Simple -(0 `max` (width-title_width-mini_icon_width-IconTitleSpacing)) / 2 + mini_icon_width + IconTitleSpacing=( (int 0)(max)( (str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing) ) )(divide)(int 2)(add)(str mini_icon_width)(add)(str IconTitleSpacing) - -# Simple -(0 `max` (width-title_width-mini_icon_width-IconTitleSpacing)) / 2 + mini_icon_width + IconTitleSpacing + 1=( (int 0)(max)( (str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing) ) )(divide)(int 2)(add)(str mini_icon_width)(add)(str IconTitleSpacing)(add)(int 1) - -# Outcrop -(0 `max` (width-title_width-mini_icon_width-IconTitleSpacing)) / 2 + mini_icon_width + IconTitleSpacing +1=( (int 0)(max)( (str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing) ) )(divide)(int 2)(add)(str mini_icon_width)(add)(str IconTitleSpacing)(add)(int 1) - -# Aquarius, Carved2, Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, Gilouche, GiloucheIM, River, SmoothGNOME, TangoDance, c2 -(3 `max` (width-title_width)) / 2=( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2) - -# Aquarius, Carved2, Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, River, SmoothGNOME, TangoDance, c2 -(3 `max` (width-title_width)) / 2 + 1=( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2)(add)(int 1) - -# Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks2-Squared, Clearlooks2-Squared-Berries, River, SmoothGNOME, TangoDance, c2 -(3 `max` (width-title_width)) / 2 + 2=( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2)(add)(int 2) - -# Bright -(3 `max` (width-title_width)) / 2+2=( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2)(add)(int 2) - -# Sandwish -(4+title_width+20) `min` (title_width-30)=( (int 4)(add)(str title_width)(add)(int 20) )(min)( (str title_width)(subtract)(int 30) ) - -# Sandwish -(4+title_width+291-34) `min` (width-4)=( (int 4)(add)(str title_width)(add)(int 291)(subtract)(int 34) )(min)( (str width)(subtract)(int 4) ) - -# Chiro, c2 -(ButtonIPad+1) + 1=( (str ButtonIPad)(add)(int 1) )(add)(int 1) - -# Esco -(height - (ButtonIPad + 1) * 2) * 0.4=( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.4) - -# Esco -(height - (ButtonIPad + 1) * 2) * 0.4 + 1=( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.4)(add)(int 1) - -# Esco -(height - (ButtonIPad + 1) * 2) * 0.67=( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.67) - -# AgingGorilla, Crux, Gorilla, Sandwish, Soft Squares, Tactile, ThinMC -(height - object_height) / 2=( (str height)(subtract)(str object_height) )(divide)(int 2) - -# Graphite -(height - title_height + 2) / 2=( (str height)(subtract)(str title_height)(add)(int 2) )(divide)(int 2) - -# Agata, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Black, Correcamins, Firey 1.0, Firey Dark, Graphite, Maemo, Redmond, Silverado, Soft Squares, Tactile, ThinMC -(height - title_height) / 2=( (str height)(subtract)(str title_height) )(divide)(int 2) - -# Agata, Black, Firey 1.0, Firey Dark -(height - title_height) / 2 + 1=( (str height)(subtract)(str title_height) )(divide)(int 2)(add)(int 1) - -# Agata -(height - title_height) / 2 - 1=( (str height)(subtract)(str title_height) )(divide)(int 2)(subtract)(int 1) - -# Maemo -(height - title_height) / 2+1=( (str height)(subtract)(str title_height) )(divide)(int 2)(add)(int 1) - -# sky, sky-blue -(height - title_height) / 5=( (str height)(subtract)(str title_height) )(divide)(int 5) - -# Esco -(height / 2) - (mini_icon_height / 2)=( (str height)(divide)(int 2) )(subtract)( (str mini_icon_height)(divide)(int 2) ) - -# Esco -(height / 2) - (mini_icon_height / 2) - 2=( (str height)(divide)(int 2) )(subtract)( (str mini_icon_height)(divide)(int 2) )(subtract)(int 2) - -# Esco -(height / 2) - (title_height / 2)=( (str height)(divide)(int 2) )(subtract)( (str title_height)(divide)(int 2) ) - -# Esco -(height / 2) - (title_height / 2) - 1=( (str height)(divide)(int 2) )(subtract)( (str title_height)(divide)(int 2) )(subtract)(int 1) - -# Esco -(height / 2) - (title_height / 2) - 2=( (str height)(divide)(int 2) )(subtract)( (str title_height)(divide)(int 2) )(subtract)(int 2) - -# Atlanta -(height-(ArrowSpacer*2)) `max` MinArrowSize=( (str height)(subtract)( (str ArrowSpacer)(multiply)(int 2) ) )(max)(str MinArrowSize) - -# Outcrop -(height-1)-(title_height /1.5)=( (str height)(subtract)(int 1) )(subtract)( (str title_height)(divide)(double 1.5) ) - -# Clearlooks-2.0-blend, Gilouche, GiloucheIM, TangoDance -(height-10)/2=( (str height)(subtract)(int 10) )(divide)(int 2) - -# Atlanta, Bright, Metabox, Outcrop -(height-mini_icon_height) / 2=( (str height)(subtract)(str mini_icon_height) )(divide)(int 2) - -# Aquarius, Clearlooks-RedExit, Firey 1.0, Firey Dark, Gilouche, GiloucheIM -(height-mini_icon_height)/2=( (str height)(subtract)(str mini_icon_height) )(divide)(int 2) - -# Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, TangoDance -(height-mini_icon_height)/2+1=( (str height)(subtract)(str mini_icon_height) )(divide)(int 2)(add)(int 1) - -# Vista Basic -(height-mini_icon_height)/2-1=( (str height)(subtract)(str mini_icon_height) )(divide)(int 2)(subtract)(int 1) - -# boxx -(height-object_height)/2=( (str height)(subtract)(str object_height) )(divide)(int 2) - -# boxx -(height-object_height)/2+1=( (str height)(subtract)(str object_height) )(divide)(int 2)(add)(int 1) - -# 4DWM, MWM -(height-title_height)/2=( (str height)(subtract)(str title_height) )(divide)(int 2) - -# Tetelestai-Modern -(height/2)-3=( (str height)(divide)(int 2) )(subtract)(int 3) - -# Tetelestai-Modern -(height/2)-4=( (str height)(divide)(int 2) )(subtract)(int 4) - -# Sloth -(height/2)-5=( (str height)(divide)(int 2) )(subtract)(int 5) - -# Crux -(left_width + ButtonWidth + IconTitleSpacing + title_width) `min` (width - right_width - 3 * ButtonWidth - CenterTitlePieceWidth * height / 22 - 3)=( (str left_width)(add)(str ButtonWidth)(add)(str IconTitleSpacing)(add)(str title_width) )(min)( (str width)(subtract)(str right_width)(subtract)(int 3)(multiply)(str ButtonWidth)(subtract)(str CenterTitlePieceWidth)(multiply)(str height)(divide)(int 22)(subtract)(int 3) ) - -# Chiro, c2 -(title_height + 6)/2=( (str title_height)(add)(int 6) )(divide)(int 2) - -# Chiro, c2 -(title_height + 6)/2+1=( (str title_height)(add)(int 6) )(divide)(int 2)(add)(int 1) - -# Esco -(width - (ButtonIPad + 1) * 2) * 0.67=( (str width)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.67) - -# AgingGorilla, Crux, Gorilla, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Sandwish, Soft Squares, Tactile, ThinMC -(width - object_width) / 2=( (str width)(subtract)(str object_width) )(divide)(int 2) - -# Crux, Sandwish -(width - title_width - height / 2 - 32 - 7) `max` 0=( (str width)(subtract)(str title_width)(subtract)(str height)(divide)(int 2)(subtract)(int 32)(subtract)(int 7) )(max)(int 0) - -# Crux -(width - title_width - left_width - ButtonWidth - IconTitleSpacing - CenterTitlePieceWidth * height / 22 - right_width) `max` (3 * ButtonWidth)=( (str width)(subtract)(str title_width)(subtract)(str left_width)(subtract)(str ButtonWidth)(subtract)(str IconTitleSpacing)(subtract)(str CenterTitlePieceWidth)(multiply)(str height)(divide)(int 22)(subtract)(str right_width) )(max)( (int 3)(multiply)(str ButtonWidth) ) - -# Sandwish -(width - title_width - left_width - ButtonWidth - IconTitleSpacing - right_width) `max` (3 * ButtonWidth)=( (str width)(subtract)(str title_width)(subtract)(str left_width)(subtract)(str ButtonWidth)(subtract)(str IconTitleSpacing)(subtract)(str right_width) )(max)( (int 3)(multiply)(str ButtonWidth) ) - -# Agata, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Black, Firey 1.0, Firey Dark, Soft Squares, Tactile -(width - title_width) / 2=( (str width)(subtract)(str title_width) )(divide)(int 2) - -# Agata, Black -(width - title_width) / 2 +1=( (str width)(subtract)(str title_width) )(divide)(int 2)(add)(int 1) - -# Agata -(width - title_width) / 2 -1=( (str width)(subtract)(str title_width) )(divide)(int 2)(subtract)(int 1) - -# Sandwish -(width -183) `max` 0=( (str width)(subtract)(int 183) )(max)(int 0) - -# Graphite -(width -title_width + 2) / 2=( (str width)(subtract)(str title_width)(add)(int 2) )(divide)(int 2) - -# Graphite -(width -title_width) / 2=( (str width)(subtract)(str title_width) )(divide)(int 2) - -# Carved2 -(width / 2) + 3=( (str width)(divide)(int 2) )(add)(int 3) - -# Carved2 -(width / 2) - 3=( (str width)(divide)(int 2) )(subtract)(int 3) - -# Atlanta -(width-(ArrowSpacer*2)) `max` MinArrowSize=( (str width)(subtract)( (str ArrowSpacer)(multiply)(int 2) ) )(max)(str MinArrowSize) - -# Clearlooks-2.0-blend, Gilouche, GiloucheIM, TangoDance -(width-10)/2=( (str width)(subtract)(int 10) )(divide)(int 2) - -# boxx -(width-18-title_width-18)/18*18+9=( (str width)(subtract)(int 18)(subtract)(str title_width)(subtract)(int 18) )(divide)(int 18)(multiply)(int 18)(add)(int 9) - -# Metabox -(width-ButtonIPad)/2+1=( (str width)(subtract)(str ButtonIPad) )(divide)(int 2)(add)(int 1) - -# Clearlooks-RedExit, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Mista -(width-mini_icon_width)/2=( (str width)(subtract)(str mini_icon_width) )(divide)(int 2) - -# Aquarius, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, TangoDance, Vista Basic -(width-mini_icon_width)/2-2=( (str width)(subtract)(str mini_icon_width) )(divide)(int 2)(subtract)(int 2) - -# MWM -(width-title_width)/2 `max` 10=( (str width)(subtract)(str title_width) )(divide)(int 2)(max)(int 10) - -# 4DWM, Agata, AgingGorilla, Almond, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Black, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Correcamins, Crux, EasyListening, Esco, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Gorilla, Graphite, MWM, Maemo, MetaGrip, Metabox, Mista, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Sandwish, Shiny, Shiny-Tango, Silverado, Simple, Simplebox, Sloth , SmoothGNOME, Soft Squares, Tactile, TangoDance, Tetelestai-Modern, ThinMC, Vista Basic, W2k, boxx, c2, pOS, sky, sky-blue -0={0==}(int 0) - -# Esco -0 - 25={-25==}(int 0)(subtract)(int 25) - -# Clearbox-look-2 -0 `max` ((height-title_height)/2)=(int 0)(max)( ( (str height)(subtract)(str title_height) )(divide)(int 2) ) - -# Bentham -0 `max` ((width-title_width)) / 2 - height=(int 0)(max)( ( (str width)(subtract)(str title_width) ) )(divide)(int 2)(subtract)(str height) - -# Vista Basic -0+1={1==}(int 0)(add)(int 1) - -# Vista Basic -0+2={2==}(int 0)(add)(int 2) - -# Amiga -0.125 * height=(double 0.125)(multiply)(str height) - -# Amiga -0.125 * width=(double 0.125)(multiply)(str width) - -# Amiga, AmigaRelief -0.25 * height=(double 0.25)(multiply)(str height) - -# Amiga, AmigaRelief -0.25 * width=(double 0.25)(multiply)(str width) - -# AmigaRelief -0.3 * height=(double 0.3)(multiply)(str height) - -# AmigaRelief -0.3 * width=(double 0.3)(multiply)(str width) - -# Amiga, AmigaRelief -0.35 * height=(double 0.35)(multiply)(str height) - -# Amiga, AmigaRelief -0.35 * width=(double 0.35)(multiply)(str width) - -# Amiga, AmigaRelief -0.375 * height=(double 0.375)(multiply)(str height) - -# Amiga, AmigaRelief -0.375 * width=(double 0.375)(multiply)(str width) - -# Amiga, AmigaRelief -0.4 * height=(double 0.4)(multiply)(str height) - -# Amiga, AmigaRelief -0.4 * width=(double 0.4)(multiply)(str width) - -# Amiga, AmigaRelief -0.5 * height=(double 0.5)(multiply)(str height) - -# Amiga, AmigaRelief -0.5 * width=(double 0.5)(multiply)(str width) - -# Amiga, AmigaRelief -0.525 * height=(double 0.525)(multiply)(str height) - -# AmigaRelief -0.525 * width=(double 0.525)(multiply)(str width) - -# AmigaRelief -0.6 * height=(double 0.6)(multiply)(str height) - -# AmigaRelief -0.6 * width=(double 0.6)(multiply)(str width) - -# AmigaRelief -0.625 * height=(double 0.625)(multiply)(str height) - -# AmigaRelief -0.625 * width=(double 0.625)(multiply)(str width) - -# AmigaRelief -0.65 * height=(double 0.65)(multiply)(str height) - -# AmigaRelief -0.7 * height=(double 0.7)(multiply)(str height) - -# AmigaRelief -0.7 * width=(double 0.7)(multiply)(str width) - -# AmigaRelief -0.75 * height=(double 0.75)(multiply)(str height) - -# AmigaRelief -0.75 * width=(double 0.75)(multiply)(str width) - -# 4DWM, AgingGorilla, Almond, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, Esco, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Gorilla, MWM, Maemo, MetaGrip, Metabox, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Shiny, Shiny-Tango, Silverado, Simple, Simplebox, SmoothGNOME, Soft Squares, Tactile, TangoDance, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -1={1==}(int 1) - -# Clearbox-look-2 -1 `max` ((height-title_height)/2)+1=(int 1)(max)( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(add)(int 1) - -# Almond, MetaGrip, Shiny, Shiny-Tango -1 `max` ((height-title_height)/2)-1=(int 1)(max)( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(subtract)(int 1) - -# Agata, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Amiga, AmigaRelief, Black, Clearlooks-2.0-blend, Gilouche, GiloucheIM, Maemo, Outcrop, Shiny, Shiny-Tango, Sloth , TangoDance, pOS, sky, sky-blue -10={10==}(int 10) - -# MetaGrip -1024={1024==}(int 1024) - -# MetaGrip, Shiny, Shiny-Tango -11={11==}(int 11) - -# Almond, Shiny, Shiny-Tango -12={12==}(int 12) - -# Shiny -13={13==}(int 13) - -# Almond, Sloth -14={14==}(int 14) - -# sky, sky-blue -15={15==}(int 15) - -# Almond, Graphite, Maemo, MetaGrip, Shiny, Shiny-Tango, sky, sky-blue -16={16==}(int 16) - -# boxx -1600={1600==}(int 1600) - -# Agata, Maemo, boxx -17={17==}(int 17) - -# EasyListening, MetaGrip, Shiny, Shiny-Tango, boxx -19={19==}(int 19) - -# 4DWM, AgingGorilla, Almond, Amiga, AmigaRelief, Aquarius, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, EasyListening, Esco, Gilouche, GiloucheIM, Gorilla, MWM, Maemo, Mista, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, River, Sandwish, Shiny, Shiny-Tango, Silverado, Simple, Simplebox, Sloth , SmoothGNOME, Tactile, TangoDance, Tetelestai-Modern, ThinMC, Vista Basic, boxx, c2, pOS -2={2==}(int 2) - -# Redmond -2 + ButtonIPad=(int 2)(add)(str ButtonIPad) - -# Shiny, Shiny-Tango -2 `max` ((height-title_height)/2)=(int 2)(max)( ( (str height)(subtract)(str title_height) )(divide)(int 2) ) - -# Firey 1.0, Firey Dark, Maemo, MetaGrip, Shiny, Shiny-Tango -20={20==}(int 20) - -# Shiny, Shiny-Tango -21={21==}(int 21) - -# Soft Squares -22={22==}(int 22) - -# Graphite, MetaGrip, Shiny, Shiny-Tango, sky, sky-blue -23={23==}(int 23) - -# Almond, Maemo, Shiny, Shiny-Tango -24={24==}(int 24) - -# Agata -25={25==}(int 25) - -# 4DWM, AgingGorilla, Amiga, AmigaRelief, Aquarius, Bright, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, EasyListening, Esco, Gilouche, GiloucheIM, Gorilla, Maemo, MetaGrip, Mista, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Sandwish, Shiny, Shiny-Tango, Sloth , SmoothGNOME, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -3={3==}(int 3) - -# Atlanta, Bright, Metabox, Redmond, Simple, SmoothGNOME, Tetelestai-Modern -3 + ButtonIPad=(int 3)(add)(str ButtonIPad) - -# SmoothGNOME -3 + ButtonIPad+1=(int 3)(add)(str ButtonIPad)(add)(int 1) - -# Chiro, Maemo, SmoothGNOME -32={32==}(int 32) - -# Outcrop -36={36==}(int 36) - -# Graphite -39={39==}(int 39) - -# 4DWM, Agata, AgingGorilla, Almond, Amiga, AmigaRelief, Aquarius, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, EasyListening, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Gorilla, MWM, Maemo, MetaGrip, Redmond, River, Sandwish, Silverado, Simplebox, Sloth , SmoothGNOME, W2k, boxx, c2, pOS -4={4==}(int 4) - -# Clearbox-look-2 -4 `max` (width-title_width)/2=(int 4)(max)( (str width)(subtract)(str title_width) )(divide)(int 2) - -# sky, sky-blue -40={40==}(int 40) - -# TangoDance -48={48==}(int 48) - -# 4DWM, AgingGorilla, Almond, AmigaRelief, Aquarius, Black, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Correcamins, Crux, Gorilla, MWM, MetaGrip, Outcrop, Redmond, Sandwish, Shiny, Shiny-Tango, Simplebox, Sloth , Tactile, ThinMC, Vista Basic, pOS -5={5==}(int 5) - -# Almond, Clearbox-look-2, MetaGrip, Shiny, Shiny-Tango -5 `max` (width-title_width)/2+1=(int 5)(max)( (str width)(subtract)(str title_width) )(divide)(int 2)(add)(int 1) - -# 4DWM, AgingGorilla, Clearbox-in, Clearbox-out, Clearlooks-RedExit, Firey 1.0, Firey Dark, Gorilla, Graphite, MWM, Maemo, Outcrop, Simplebox, Soft Squares, Vista Basic, pOS -6={6==}(int 6) - -# Shiny, Shiny-Tango -6 `max` (width-title_width)/2+2=(int 6)(max)( (str width)(subtract)(str title_width) )(divide)(int 2)(add)(int 2) - -# 4DWM, Almond, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Clearbox-in, Clearbox-out, MWM, MetaGrip, Outcrop, Shiny, Shiny-Tango, Simplebox, pOS -7={7==}(int 7) - -# 4DWM, AgingGorilla, Almond, Clearlooks-RedExit, Gorilla, Maemo, Outcrop, Shiny, Sloth , Tactile, pOS -8={8==}(int 8) - -# Clearlooks-RedExit -8 + top_height - 16=(int 8)(add)(str top_height)(subtract)(int 16) - -# Vista Basic -87={87==}(int 87) - -# Clearbox-in, Clearbox-out, Outcrop, Shiny, Shiny-Tango, Simplebox, Vista Basic, pOS, sky, sky-blue -9={9==}(int 9) - -# Atlanta -ArrowSpacer `min` (height-MinArrowSize)/2=(str ArrowSpacer)(min)( (str height)(subtract)(str MinArrowSize) )(divide)(int 2) - -# Atlanta -ArrowSpacer `min` (width-MinArrowSize)/2=(str ArrowSpacer)(min)( (str width)(subtract)(str MinArrowSize) )(divide)(int 2) - -# Atlanta, Bright, Carved2, Chiro, Esco, Metabox, Redmond, River, Simple, SmoothGNOME, Tetelestai-Modern, c2 -ButtonIPad=(str ButtonIPad) - -# Esco -ButtonIPad + (height - (ButtonIPad + 1) * 2) * 0.33=(str ButtonIPad)(add)( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.33) - -# Esco -ButtonIPad + (height - (ButtonIPad + 1) * 2) * 0.33 + 1=(str ButtonIPad)(add)( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.33)(add)(int 1) - -# Esco -ButtonIPad + (width - (ButtonIPad + 1) * 2) * 0.33=(str ButtonIPad)(add)( (str width)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.33) - -# Esco -ButtonIPad + (width - (ButtonIPad + 1) * 2) * 0.33 + 1=(str ButtonIPad)(add)( (str width)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.33)(add)(int 1) - -# Carved2, Chiro, Esco, River, c2 -ButtonIPad + 1=(str ButtonIPad)(add)(int 1) - -# Esco -ButtonIPad + 1 + 1=(str ButtonIPad)(add)(int 1)(add)(int 1) - -# Chiro, River, c2 -ButtonIPad + 2=(str ButtonIPad)(add)(int 2) - -# Chiro, River, c2 -ButtonIPad + 3=(str ButtonIPad)(add)(int 3) - -# Carved2, Chiro, Esco, Metabox, Redmond, River, Simple, Tetelestai-Modern, c2 -ButtonIPad - 1=(str ButtonIPad)(subtract)(int 1) - -# Esco -ButtonIPad - 1 + 1=(str ButtonIPad)(subtract)(int 1)(add)(int 1) - -# Atlanta, Bright, Chiro, Metabox, Redmond, Simple, SmoothGNOME, Tetelestai-Modern, c2 -ButtonIPad+1=(str ButtonIPad)(add)(int 1) - -# Simple -ButtonIPad+2=(str ButtonIPad)(add)(int 2) - -# Redmond, SmoothGNOME -ButtonIPad-1=(str ButtonIPad)(subtract)(int 1) - -# Clearbox-look-2 -ButtonPad=(str ButtonPad) - -# Clearbox-look-2 -ButtonPad+(height-ButtonPad)/6=(str ButtonPad)(add)( (str height)(subtract)(str ButtonPad) )(divide)(int 6) - -# Clearbox-look-2 -ButtonPad+(height-ButtonPad)/6-1=(str ButtonPad)(add)( (str height)(subtract)(str ButtonPad) )(divide)(int 6)(subtract)(int 1) - -# Clearbox-look-2 -ButtonPad+1=(str ButtonPad)(add)(int 1) - -# Clearbox-look-2 -ButtonPad+2=(str ButtonPad)(add)(int 2) - -# Clearbox-look-2 -ButtonPad+3=(str ButtonPad)(add)(int 3) - -# Clearbox-look-2 -ButtonPad-1=(str ButtonPad)(subtract)(int 1) - -# Clearbox-look-2 -ButtonPad-2=(str ButtonPad)(subtract)(int 2) - -# Mista -CaptionStart=(str CaptionStart) - -# AgingGorilla, Crux, Gorilla, Sandwish -IconTitleSpacing=(str IconTitleSpacing) - -# Clearbox-look-2 -PrelightPad=(str PrelightPad) - -# Clearbox-look-2 -PrelightPad+(height-PrelightPad)/6=(str PrelightPad)(add)( (str height)(subtract)(str PrelightPad) )(divide)(int 6) - -# Clearbox-look-2 -PrelightPad+(height-PrelightPad)/6-1=(str PrelightPad)(add)( (str height)(subtract)(str PrelightPad) )(divide)(int 6)(subtract)(int 1) - -# Clearbox-look-2 -PrelightPad+1=(str PrelightPad)(add)(int 1) - -# Clearbox-look-2 -PrelightPad+2=(str PrelightPad)(add)(int 2) - -# Clearbox-look-2 -PrelightPad+3=(str PrelightPad)(add)(int 3) - -# Clearbox-look-2 -PrelightPad-1=(str PrelightPad)(subtract)(int 1) - -# Clearbox-look-2 -PrelightPad-2=(str PrelightPad)(subtract)(int 2) - -# Carved2 -ResizerWidth=(str ResizerWidth) - -# Carved2 -ResizerWidth + 1=(str ResizerWidth)(add)(int 1) - -# Mista -TitlebarPad=(str TitlebarPad) - -# Silverado -bottom_height=(str bottom_height) - -# Carved2 -bottom_height - 3=(str bottom_height)(subtract)(int 3) - -# Carved2 -bottom_height - 4=(str bottom_height)(subtract)(int 4) - -# MWM, Tetelestai-Modern -bottom_height-1=(str bottom_height)(subtract)(int 1) - -# 4DWM -bottom_height-2=(str bottom_height)(subtract)(int 2) - -# 4DWM -bottom_height-4=(str bottom_height)(subtract)(int 4) - -# 4DWM, Agata, AgingGorilla, Almond, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Amiga, Atlanta, Black, Bright, Carved2, Chiro, Clearbox-in, Clearbox-out, Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Correcamins, Crux, EasyListening, Esco, Firey 1.0, Firey Dark, Gorilla, Graphite, MWM, Maemo, MetaGrip, Metabox, Mista, Outcrop, Redmond, River, Sandwish, Shiny, Shiny-Tango, Silverado, Simple, Simplebox, SmoothGNOME, Soft Squares, Tactile, TangoDance, Tetelestai-Modern, ThinMC, Vista Basic, W2k, boxx, c2, sky, sky-blue -height=(str height) - -# Esco -height + 25=(str height)(add)(int 25) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height - ((height-(Bmin`max`height-Bpad*2))/2)=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height - ((height-(Bmin`max`height-Bpad*2))/2) - 1=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height - ((height-(Bmin`max`height-Bpad*2))/2) - 2=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height - ((height-(Bmin`max`height-Bpad*2))/2)-1=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 1) - -# Esco -height - (ButtonIPad + 1) * 2=(str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) - -# AgingGorilla, Aquarius, Carved2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Gilouche, GiloucheIM, Gorilla, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Simple, SmoothGNOME, TangoDance -height - 1=(str height)(subtract)(int 1) - -# Esco -height - 1 - ButtonIPad - 1=(str height)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Esco -height - 1 - ButtonIPad - 1 + 1=(str height)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1)(add)(int 1) - -# Esco -height - 1 - ButtonIPad - 1 - 1=(str height)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1) - -# Esco -height - 1 - ButtonIPad - 1 - 1 + 1=(str height)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1)(add)(int 1) - -# AgingGorilla, Gorilla -height - 10=(str height)(subtract)(int 10) - -# AgingGorilla, Gorilla -height - 12=(str height)(subtract)(int 12) - -# AgingGorilla, Gorilla -height - 14=(str height)(subtract)(int 14) - -# AgingGorilla, Aquarius, Carved2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Gorilla, Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2, Redmond, River, Simple, SmoothGNOME -height - 2=(str height)(subtract)(int 2) - -# Esco, Gilouche, GiloucheIM, SmoothGNOME, TangoDance -height - 3=(str height)(subtract)(int 3) - -# Crux, Sandwish, SmoothGNOME -height - 4=(str height)(subtract)(int 4) - -# Atlanta, Bright, Simple -height - 5 - ButtonIPad=(str height)(subtract)(int 5)(subtract)(str ButtonIPad) - -# AgingGorilla, Esco, Gorilla -height - 7=(str height)(subtract)(int 7) - -# Metabox, Redmond, SmoothGNOME, Tetelestai-Modern -height - 7 - ButtonIPad=(str height)(subtract)(int 7)(subtract)(str ButtonIPad) - -# AgingGorilla, Gorilla -height - 8=(str height)(subtract)(int 8) - -# Carved2, Chiro, Metabox, Redmond, River, Simple, SmoothGNOME, Tetelestai-Modern, c2 -height - ButtonIPad=(str height)(subtract)(str ButtonIPad) - -# Carved2, Simple -height - ButtonIPad + 1=(str height)(subtract)(str ButtonIPad)(add)(int 1) - -# Esco -height - ButtonIPad - ((height - (ButtonIPad + 1) * 2) * 0.4)=(str height)(subtract)(str ButtonIPad)(subtract)( ( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.4) ) - -# Esco -height - ButtonIPad - ((height - (ButtonIPad + 1) * 2) * 0.4) - 1=(str height)(subtract)(str ButtonIPad)(subtract)( ( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.4) )(subtract)(int 1) - -# Atlanta, Carved2, Esco, Metabox, Redmond, SmoothGNOME, Tetelestai-Modern -height - ButtonIPad - 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Esco -height - ButtonIPad - 1 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 1)(add)(int 1) - -# Esco -height - ButtonIPad - 1 - 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1) - -# Esco -height - ButtonIPad - 1 - 1 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1)(add)(int 1) - -# Bright, Chiro, Esco, Redmond, River, SmoothGNOME, c2 -height - ButtonIPad - 2=(str height)(subtract)(str ButtonIPad)(subtract)(int 2) - -# Esco -height - ButtonIPad - 2 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 2)(add)(int 1) - -# Esco -height - ButtonIPad - 3=(str height)(subtract)(str ButtonIPad)(subtract)(int 3) - -# Esco -height - ButtonIPad - 3 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 3)(add)(int 1) - -# Esco -height - ButtonIPad - 3 - 4=(str height)(subtract)(str ButtonIPad)(subtract)(int 3)(subtract)(int 4) - -# Esco -height - ButtonIPad - 3 - 4 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 3)(subtract)(int 4)(add)(int 1) - -# Esco -height - ButtonIPad - 3 - 5=(str height)(subtract)(str ButtonIPad)(subtract)(int 3)(subtract)(int 5) - -# Esco -height - ButtonIPad - 3 - 5 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 3)(subtract)(int 5)(add)(int 1) - -# Metabox, Tetelestai-Modern -height - ButtonIPad - 4=(str height)(subtract)(str ButtonIPad)(subtract)(int 4) - -# Esco -height - ButtonIPad - 5=(str height)(subtract)(str ButtonIPad)(subtract)(int 5) - -# Esco -height - ButtonIPad - 5 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 5)(add)(int 1) - -# Atlanta, Bright, Metabox, Redmond, SmoothGNOME, Tetelestai-Modern -height - ButtonIPad - ThickLineWidth + 1=(str height)(subtract)(str ButtonIPad)(subtract)(str ThickLineWidth)(add)(int 1) - -# Simple -height - ButtonIPad - ThickLineWidth + 3=(str height)(subtract)(str ButtonIPad)(subtract)(str ThickLineWidth)(add)(int 3) - -# Chiro, River, c2 -height - ButtonIPad-1=(str height)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Quiet-Environment, Quiet-Graphite, Quiet-Human, Quiet-Purple-2K6 -height - height / 4=(str height)(subtract)(str height)(divide)(int 4) - -# Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2 -height - height / 4 + 2=(str height)(subtract)(str height)(divide)(int 4)(add)(int 2) - -# Crux, Maemo, Sandwish -height - object_height=(str height)(subtract)(str object_height) - -# Esco -height - top_height - bottom_height + 1=(str height)(subtract)(str top_height)(subtract)(str bottom_height)(add)(int 1) - -# Esco -height - top_height - bottom_height - 1=(str height)(subtract)(str top_height)(subtract)(str bottom_height)(subtract)(int 1) - -# Aquarius, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, TangoDance -height / 2=(str height)(divide)(int 2) - -# TangoDance -height / 2 - 1=(str height)(divide)(int 2)(subtract)(int 1) - -# TangoDance -height / 2 - 2=(str height)(divide)(int 2)(subtract)(int 2) - -# Aquarius, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, TangoDance -height / 2 - 3=(str height)(divide)(int 2)(subtract)(int 3) - -# Aquarius, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height / 2 - 4=(str height)(divide)(int 2)(subtract)(int 4) - -# Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2 -height / 3=(str height)(divide)(int 3) - -# Quiet-Environment, Quiet-Graphite, Quiet-Human, Quiet-Purple-2K6 -height / 4=(str height)(divide)(int 4) - -# Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2 -height / 4 + 2=(str height)(divide)(int 4)(add)(int 2) - -# Outcrop -height /2=(str height)(divide)(int 2) - -# Outcrop -height /2 +1=(str height)(divide)(int 2)(add)(int 1) - -# Outcrop -height /2 +2=(str height)(divide)(int 2)(add)(int 2) - -# Outcrop -height /2 -1=(str height)(divide)(int 2)(subtract)(int 1) - -# Bentham -height `max` ((width-title_width)) / 2=(str height)(max)( ( (str width)(subtract)(str title_width) ) )(divide)(int 2) - -# Mista -height `min` object_height=(str height)(min)(str object_height) - -# Sloth -height+1=(str height)(add)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height-((height-(Bmin`max`height-Bpad*2))/2)*2-1=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(multiply)(int 2)(subtract)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height-((height-(Bmin`max`height-Bpad*2))/2)*2-3=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(multiply)(int 2)(subtract)(int 3) - -# 4DWM -height-(2 * right_width - 1)=(str height)(subtract)( (int 2)(multiply)(str right_width)(subtract)(int 1) ) - -# Chiro, c2 -height-(ButtonIPad+1)*2-1=(str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2)(subtract)(int 1) - -# 4DWM -height-(right_width-1)=(str height)(subtract)( (str right_width)(subtract)(int 1) ) - -# 4DWM -height-(right_width-2)=(str height)(subtract)( (str right_width)(subtract)(int 2) ) - -# 4DWM, Almond, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Bright, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, MWM, MetaGrip, Metabox, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Simple, Simplebox, Sloth , SmoothGNOME, Tactile, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -height-1=(str height)(subtract)(int 1) - -# pOS -height-11=(str height)(subtract)(int 11) - -# 4DWM, AmigaRelief, Aquarius, Atlanta, Bentham, Bright, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, Gilouche, GiloucheIM, MWM, Metabox, Outcrop, River, Shiny, Shiny-Tango, Silverado, Simple, SmoothGNOME, Tactile, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -height-2=(str height)(subtract)(int 2) - -# Shiny, Shiny-Tango -height-21=(str height)(subtract)(int 21) - -# Soft Squares, Tactile -height-23=(str height)(subtract)(int 23) - -# Maemo -height-25=(str height)(subtract)(int 25) - -# Maemo -height-26=(str height)(subtract)(int 26) - -# Maemo, Shiny, Shiny-Tango -height-29=(str height)(subtract)(int 29) - -# 4DWM, Aquarius, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Gilouche, GiloucheIM, MWM, Outcrop, River, Simple, Simplebox, SmoothGNOME, Tactile, Tetelestai-Modern, W2k, c2 -height-3=(str height)(subtract)(int 3) - -# 4DWM, Amiga, AmigaRelief, Aquarius, Bright, Carved2, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, Maemo, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, River, Sandwish, SmoothGNOME, Tetelestai-Modern, W2k, c2, pOS -height-4=(str height)(subtract)(int 4) - -# 4DWM, Almond, Amiga, AmigaRelief, Aquarius, Carved2, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, MWM, River, SmoothGNOME, Tetelestai-Modern, W2k, c2, pOS -height-5=(str height)(subtract)(int 5) - -# 4DWM, AmigaRelief, Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, EasyListening, MWM, pOS -height-6=(str height)(subtract)(int 6) - -# 4DWM, MWM, Shiny, Shiny-Tango, pOS -height-7=(str height)(subtract)(int 7) - -# 4DWM, pOS -height-8=(str height)(subtract)(int 8) - -# Almond, Outcrop, pOS -height-9=(str height)(subtract)(int 9) - -# Carved2 -height-ButtonIPad*2=(str height)(subtract)(str ButtonIPad)(multiply)(int 2) - -# Simple -height-ButtonIPad*2 + 1=(str height)(subtract)(str ButtonIPad)(multiply)(int 2)(add)(int 1) - -# Atlanta, Chiro, Metabox, Redmond, River, SmoothGNOME, Tetelestai-Modern, c2 -height-ButtonIPad*2-1=(str height)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 1) - -# Bright -height-ButtonIPad*2-2=(str height)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 2) - -# Chiro, River, c2 -height-ButtonIPad*2-5=(str height)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 5) - -# Clearbox-look-2 -height-ButtonPad=(str height)(subtract)(str ButtonPad) - -# Clearbox-look-2 -height-ButtonPad*2+1=(str height)(subtract)(str ButtonPad)(multiply)(int 2)(add)(int 1) - -# Clearbox-look-2 -height-ButtonPad*2-2=(str height)(subtract)(str ButtonPad)(multiply)(int 2)(subtract)(int 2) - -# Clearbox-look-2 -height-ButtonPad+1=(str height)(subtract)(str ButtonPad)(add)(int 1) - -# Clearbox-look-2 -height-ButtonPad-1=(str height)(subtract)(str ButtonPad)(subtract)(int 1) - -# Clearbox-look-2 -height-ButtonPad-2=(str height)(subtract)(str ButtonPad)(subtract)(int 2) - -# Clearbox-look-2 -height-PrelightPad=(str height)(subtract)(str PrelightPad) - -# Clearbox-look-2 -height-PrelightPad*2+1=(str height)(subtract)(str PrelightPad)(multiply)(int 2)(add)(int 1) - -# Clearbox-look-2 -height-PrelightPad*2-2=(str height)(subtract)(str PrelightPad)(multiply)(int 2)(subtract)(int 2) - -# Clearbox-look-2 -height-PrelightPad+1=(str height)(subtract)(str PrelightPad)(add)(int 1) - -# Clearbox-look-2 -height-PrelightPad-1=(str height)(subtract)(str PrelightPad)(subtract)(int 1) - -# Clearbox-look-2 -height-PrelightPad-2=(str height)(subtract)(str PrelightPad)(subtract)(int 2) - -# Chiro, Gilouche, GiloucheIM, SmoothGNOME, Tetelestai-Modern -height-bottom_height=(str height)(subtract)(str bottom_height) - -# Carved2 -height-bottom_height + 1=(str height)(subtract)(str bottom_height)(add)(int 1) - -# Carved2 -height-bottom_height + 2=(str height)(subtract)(str bottom_height)(add)(int 2) - -# 4DWM, MWM -height-bottom_height+1=(str height)(subtract)(str bottom_height)(add)(int 1) - -# Gilouche, GiloucheIM -height-bottom_height-top_height=(str height)(subtract)(str bottom_height)(subtract)(str top_height) - -# 4DWM -height-bottom_height/2=(str height)(subtract)(str bottom_height)(divide)(int 2) - -# Mista -height-object_height=(str height)(subtract)(str object_height) - -# 4DWM, MWM -height-right_width=(str height)(subtract)(str right_width) - -# MWM -height-right_width-1=(str height)(subtract)(str right_width)(subtract)(int 1) - -# c2 -height-title_height=(str height)(subtract)(str title_height) - -# Chiro, SmoothGNOME -height-title_height-38=(str height)(subtract)(str title_height)(subtract)(int 38) - -# Amiga, AmigaRelief, c2, pOS -height-title_height-6=(str height)(subtract)(str title_height)(subtract)(int 6) - -# 4DWM, MWM -height-top_height=(str height)(subtract)(str top_height) - -# 4DWM -height-top_height+1=(str height)(subtract)(str top_height)(add)(int 1) - -# 4DWM, MWM, Tactile -height-top_height-1=(str height)(subtract)(str top_height)(subtract)(int 1) - -# 4DWM -height-top_height-2=(str height)(subtract)(str top_height)(subtract)(int 2) - -# Atlanta, Bright, Metabox, Simple, SmoothGNOME, TangoDance, Tetelestai-Modern -height-top_height-bottom_height+1=(str height)(subtract)(str top_height)(subtract)(str bottom_height)(add)(int 1) - -# Sloth -height/1.5=(str height)(divide)(double 1.5) - -# 4DWM, Aquarius, Bentham, Clearbox-in, Clearbox-out, MWM, Simplebox, Sloth , Tetelestai-Modern -height/2=(str height)(divide)(int 2) - -# Bentham -height/2 + height/4 - 1=(str height)(divide)(int 2)(add)(str height)(divide)(int 4)(subtract)(int 1) - -# Bentham -height/2 + height/4 - 2=(str height)(divide)(int 2)(add)(str height)(divide)(int 4)(subtract)(int 2) - -# Bentham -height/2 - height/4=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 4) - -# Bentham -height/2 - height/4 + 1=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 4)(add)(int 1) - -# Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2 -height/2 - width/2=(str height)(divide)(int 2)(subtract)(str width)(divide)(int 2) - -# Amiga, AmigaRelief -height/2 - width/2 + 2=(str height)(divide)(int 2)(subtract)(str width)(divide)(int 2)(add)(int 2) - -# Clearbox-look-2 -height/2+(height-ButtonPad)/6+1=(str height)(divide)(int 2)(add)( (str height)(subtract)(str ButtonPad) )(divide)(int 6)(add)(int 1) - -# Clearbox-look-2 -height/2+(height-PrelightPad)/6+1=(str height)(divide)(int 2)(add)( (str height)(subtract)(str PrelightPad) )(divide)(int 6)(add)(int 1) - -# 4DWM, Aquarius, Clearbox-in, Clearbox-out, Simplebox -height/2+1=(str height)(divide)(int 2)(add)(int 1) - -# 4DWM, Clearbox-in, Clearbox-out, MWM, Simplebox -height/2+2=(str height)(divide)(int 2)(add)(int 2) - -# 4DWM, Clearbox-in, Clearbox-out, Simplebox -height/2+3=(str height)(divide)(int 2)(add)(int 3) - -# Clearbox-in, Clearbox-out, Simplebox -height/2+4=(str height)(divide)(int 2)(add)(int 4) - -# Clearbox-in, Clearbox-out, Simplebox -height/2+5=(str height)(divide)(int 2)(add)(int 5) - -# Clearbox-in, Clearbox-out, Simplebox -height/2+6=(str height)(divide)(int 2)(add)(int 6) - -# Aquarius -height/2+height/4=(str height)(divide)(int 2)(add)(str height)(divide)(int 4) - -# Aquarius -height/2+height/4-1=(str height)(divide)(int 2)(add)(str height)(divide)(int 4)(subtract)(int 1) - -# Clearbox-in, Clearbox-out, MWM, Simplebox -height/2-1=(str height)(divide)(int 2)(subtract)(int 1) - -# 4DWM, Aquarius, Clearbox-in, Clearbox-out, Simplebox -height/2-2=(str height)(divide)(int 2)(subtract)(int 2) - -# Clearbox-in, Clearbox-out, Outcrop, Simplebox -height/2-3=(str height)(divide)(int 2)(subtract)(int 3) - -# Clearbox-in, Clearbox-out, Outcrop, Simplebox -height/2-4=(str height)(divide)(int 2)(subtract)(int 4) - -# Clearbox-in, Clearbox-out, Simplebox -height/2-5=(str height)(divide)(int 2)(subtract)(int 5) - -# Aquarius -height/2-5+(2`max`height/8)=(str height)(divide)(int 2)(subtract)(int 5)(add)( (int 2)(max)(str height)(divide)(int 8) ) - -# Aquarius -height/2-height/4=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 4) - -# Aquarius -height/2-height/4+1=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 4)(add)(int 1) - -# Aquarius -height/2-height/4+2=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 4)(add)(int 2) - -# Aquarius -height/2-height/6+1=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 6)(add)(int 1) - -# Aquarius -height/2-height/6+2=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 6)(add)(int 2) - -# Bentham -height/2-height/8-1=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 8)(subtract)(int 1) - -# Bentham -height/2-height/8-2=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 8)(subtract)(int 2) - -# Aquarius -height/3+1=(str height)(divide)(int 3)(add)(int 1) - -# Aquarius -height/3-1=(str height)(divide)(int 3)(subtract)(int 1) - -# Aquarius -height/3-3=(str height)(divide)(int 3)(subtract)(int 3) - -# Bentham -height/4=(str height)(divide)(int 4) - -# Bentham -height/4+2=(str height)(divide)(int 4)(add)(int 2) - -# 4DWM, Esco, Gilouche, GiloucheIM, MWM, Silverado -left_width=(str left_width) - -# Esco -left_width - 1=(str left_width)(subtract)(int 1) - -# 4DWM, Atlanta, Bright, Chiro, Gilouche, GiloucheIM, MWM, Metabox, Simple, SmoothGNOME, TangoDance, Tetelestai-Modern -left_width-1=(str left_width)(subtract)(int 1) - -# 4DWM, Tetelestai-Modern -left_width-2=(str left_width)(subtract)(int 2) - -# 4DWM -left_width-3=(str left_width)(subtract)(int 3) - -# Aquarius, Atlanta, Clearlooks-2.0-blend, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Metabox, Mista, Outcrop, Silverado, TangoDance, Vista Basic, W2k -mini_icon_height=(str mini_icon_height) - -# Bright -mini_icon_height-1=(str mini_icon_height)(subtract)(int 1) - -# Aquarius, Atlanta, Clearlooks-2.0-blend, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Metabox, Mista, Outcrop, Silverado, Sloth , TangoDance, Vista Basic, W2k -mini_icon_width=(str mini_icon_width) - -# Esco -mini_icon_width + IconTitleSpacing=(str mini_icon_width)(add)(str IconTitleSpacing) - -# Bright -mini_icon_width-1=(str mini_icon_width)(subtract)(int 1) - -# Agata, AgingGorilla, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Black, Correcamins, Crux, Firey 1.0, Firey Dark, Gorilla, Graphite, Maemo, Mista, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Sandwish, Soft Squares, Tactile, ThinMC, Vista Basic, boxx, sky, sky-blue -object_height=(str object_height) - -# Maemo -object_height+2=(str object_height)(add)(int 2) - -# Agata, AgingGorilla, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Black, Correcamins, Crux, Firey 1.0, Firey Dark, Gorilla, Graphite, Maemo, Mista, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Sandwish, Silverado, Soft Squares, Tactile, ThinMC, Vista Basic, W2k, sky, sky-blue -object_width=(str object_width) - -# Crux -object_width * height / 22=(str object_width)(multiply)(str height)(divide)(int 22) - -# Maemo -object_width+2=(str object_width)(add)(int 2) - -# 4DWM, MWM, Silverado -right_width=(str right_width) - -# 4DWM, MWM -right_width-1=(str right_width)(subtract)(int 1) - -# 4DWM, Tetelestai-Modern -right_width-2=(str right_width)(subtract)(int 2) - -# 4DWM -right_width-3=(str right_width)(subtract)(int 3) - -# 4DWM -right_width-4=(str right_width)(subtract)(int 4) - -# Gilouche, GiloucheIM -title_height + 10=(str title_height)(add)(int 10) - -# TangoDance -title_height + 12=(str title_height)(add)(int 12) - -# Clearlooks, Clearlooks-Pinstripe, River -title_height + 3=(str title_height)(add)(int 3) - -# Chiro, SmoothGNOME -title_height + 38=(str title_height)(add)(int 38) - -# Chiro, Gilouche, GiloucheIM, River, SmoothGNOME, TangoDance, c2 -title_height + 4=(str title_height)(add)(int 4) - -# Chiro, Clearlooks, Clearlooks-Pinstripe, Gilouche, GiloucheIM, River, SmoothGNOME, TangoDance, c2 -title_height + 5=(str title_height)(add)(int 5) - -# Clearlooks, Clearlooks-Pinstripe, SmoothGNOME, c2 -title_height + 6=(str title_height)(add)(int 6) - -# TangoDance -title_height + 9=(str title_height)(add)(int 9) - -# Outcrop -title_height +8=(str title_height)(add)(int 8) - -# Outcrop -title_height -7=(str title_height)(subtract)(int 7) - -# TangoDance -title_height / 2 - 5=(str title_height)(divide)(int 2)(subtract)(int 5) - -# Outcrop -title_height /1.5=(str title_height)(divide)(double 1.5) - -# Outcrop -title_height /2=(str title_height)(divide)(int 2) - -# Outcrop -title_height /4=(str title_height)(divide)(int 4) - -# 4DWM -title_height*2/3=(str title_height)(multiply)(int 2)(divide)(int 3) - -# AmigaRelief, pOS -title_height+3=(str title_height)(add)(int 3) - -# Amiga, AmigaRelief, Clearbox-look-2, pOS -title_height+4=(str title_height)(add)(int 4) - -# Amiga, AmigaRelief, pOS -title_height+5=(str title_height)(add)(int 5) - -# Chiro, Outcrop, SmoothGNOME, c2 -title_height+6=(str title_height)(add)(int 6) - -# Outcrop -title_height+7=(str title_height)(add)(int 7) - -# Outcrop -title_height+8=(str title_height)(add)(int 8) - -# sky, sky-blue -title_width + 16 `min` width - 14=(str title_width)(add)(int 16)(min)(str width)(subtract)(int 14) - -# sky, sky-blue -title_width + 21 `min` width - object_width=(str title_width)(add)(int 21)(min)(str width)(subtract)(str object_width) - -# sky, sky-blue -title_width + 6=(str title_width)(add)(int 6) - -# Esco -title_width + mini_icon_width + IconTitleSpacing * 3 - 1=(str title_width)(add)(str mini_icon_width)(add)(str IconTitleSpacing)(multiply)(int 3)(subtract)(int 1) - -# boxx -title_width+15=(str title_width)(add)(int 15) - -# Maemo -title_width+181=(str title_width)(add)(int 181) - -# Sandwish -title_width+20=(str title_width)(add)(int 20) - -# Maemo -title_width+32=(str title_width)(add)(int 32) - -# Maemo -title_width+32+149=(str title_width)(add)(int 32)(add)(int 149) - -# boxx -title_width-2=(str title_width)(subtract)(int 2) - -# Sandwish -title_width/2+150=(str title_width)(divide)(int 2)(add)(int 150) - -# 4DWM, Chiro, Clearbox-in, Clearbox-out, Esco, MWM, Simplebox -top_height=(str top_height) - -# Clearlooks-RedExit, Esco -top_height - 1=(str top_height)(subtract)(int 1) - -# Clearlooks-RedExit -top_height - 16=(str top_height)(subtract)(int 16) - -# Clearlooks-RedExit -top_height - 2=(str top_height)(subtract)(int 2) - -# Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -top_height / 2=(str top_height)(divide)(int 2) - -# Aquarius -top_height*2/5=(str top_height)(multiply)(int 2)(divide)(int 5) - -# Aquarius -top_height*3/10=(str top_height)(multiply)(int 3)(divide)(int 10) - -# Aquarius -top_height*3/5=(str top_height)(multiply)(int 3)(divide)(int 5) - -# Aquarius -top_height*4/5=(str top_height)(multiply)(int 4)(divide)(int 5) - -# Aquarius -top_height*7/10=(str top_height)(multiply)(int 7)(divide)(int 10) - -# Aquarius -top_height*9/10=(str top_height)(multiply)(int 9)(divide)(int 10) - -# 4DWM -top_height+1=(str top_height)(add)(int 1) - -# 4DWM, Aquarius, Atlanta, Bright, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Gilouche, GiloucheIM, MWM, Metabox, Simple, SmoothGNOME, Tactile, TangoDance, Tetelestai-Modern -top_height-1=(str top_height)(subtract)(int 1) - -# 4DWM, Aquarius, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -top_height-2=(str top_height)(subtract)(int 2) - -# 4DWM -top_height-3=(str top_height)(subtract)(int 3) - -# Aquarius -top_height/10=(str top_height)(divide)(int 10) - -# Aquarius -top_height/10+1=(str top_height)(divide)(int 10)(add)(int 1) - -# Aquarius -top_height/2=(str top_height)(divide)(int 2) - -# Aquarius -top_height/5=(str top_height)(divide)(int 5) - -# 4DWM, Agata, AgingGorilla, Almond, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Black, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Correcamins, Crux, EasyListening, Esco, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Gorilla, Graphite, MWM, MetaGrip, Metabox, Mista, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Sandwish, Shiny, Shiny-Tango, Silverado, Simple, Simplebox, SmoothGNOME, TangoDance, Tetelestai-Modern, ThinMC, Vista Basic, W2k, boxx, c2, pOS, sky, sky-blue -width=(str width) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width - ((width-(Bmin`max`height-Bpad*2))/2)=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width - ((width-(Bmin`max`height-Bpad*2))/2) - 1=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 1) - -# Esco -width - (ButtonIPad + 1) * 2=(str width)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) - -# sky, sky-blue -width - 0=(str width)(subtract)(int 0) - -# AgingGorilla, Aquarius, Carved2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Gilouche, GiloucheIM, Gorilla, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Simple, SmoothGNOME, Soft Squares, TangoDance -width - 1=(str width)(subtract)(int 1) - -# Esco -width - 1 - ButtonIPad=(str width)(subtract)(int 1)(subtract)(str ButtonIPad) - -# Esco -width - 1 - ButtonIPad + 1=(str width)(subtract)(int 1)(subtract)(str ButtonIPad)(add)(int 1) - -# Esco -width - 1 - ButtonIPad - 1=(str width)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Esco -width - 1 - ButtonIPad - 1 + 1=(str width)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1)(add)(int 1) - -# Agata, Black, Correcamins -width - 10=(str width)(subtract)(int 10) - -# AgingGorilla, Gorilla -width - 11=(str width)(subtract)(int 11) - -# AgingGorilla, Almond, Gorilla, Graphite, sky, sky-blue -width - 12=(str width)(subtract)(int 12) - -# AgingGorilla, Gorilla -width - 13=(str width)(subtract)(int 13) - -# AgingGorilla, Gorilla -width - 16=(str width)(subtract)(int 16) - -# AgingGorilla, Aquarius, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Gilouche, GiloucheIM, Gorilla, Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2, Redmond, River, Simple, SmoothGNOME, Soft Squares, TangoDance, ThinMC -width - 2=(str width)(subtract)(int 2) - -# Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple -width - 20=(str width)(subtract)(int 20) - -# Almond -width - 24=(str width)(subtract)(int 24) - -# Graphite, sky, sky-blue -width - 27=(str width)(subtract)(int 27) - -# Carved2, Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Gilouche, GiloucheIM, SmoothGNOME, TangoDance -width - 3=(str width)(subtract)(int 3) - -# Aquarius, Carved2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2, River, Sandwish, SmoothGNOME, Tactile, TangoDance -width - 4=(str width)(subtract)(int 4) - -# Gilouche, GiloucheIM -width - 5=(str width)(subtract)(int 5) - -# Atlanta, Bright, Simple -width - 5 - ButtonIPad=(str width)(subtract)(int 5)(subtract)(str ButtonIPad) - -# Firey 1.0, Firey Dark, Tactile -width - 6=(str width)(subtract)(int 6) - -# Agata, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Esco -width - 7=(str width)(subtract)(int 7) - -# Metabox, Redmond, SmoothGNOME, Tetelestai-Modern -width - 7 - ButtonIPad=(str width)(subtract)(int 7)(subtract)(str ButtonIPad) - -# AgingGorilla, Gorilla -width - 8=(str width)(subtract)(int 8) - -# AgingGorilla, Gorilla -width - 9=(str width)(subtract)(int 9) - -# Atlanta, Metabox, Redmond, SmoothGNOME, Tetelestai-Modern -width - ButtonIPad=(str width)(subtract)(str ButtonIPad) - -# Simple -width - ButtonIPad + 1=(str width)(subtract)(str ButtonIPad)(add)(int 1) - -# Atlanta, Esco, Redmond, SmoothGNOME, Tetelestai-Modern -width - ButtonIPad - 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Esco -width - ButtonIPad - 1 + 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1)(add)(int 1) - -# Esco -width - ButtonIPad - 1 - 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1) - -# Esco -width - ButtonIPad - 1 - 1 + 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1)(add)(int 1) - -# Bright, Esco -width - ButtonIPad - 2=(str width)(subtract)(str ButtonIPad)(subtract)(int 2) - -# Esco -width - ButtonIPad - 2 + 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 2)(add)(int 1) - -# Esco, Metabox, Tetelestai-Modern -width - ButtonIPad - 4=(str width)(subtract)(str ButtonIPad)(subtract)(int 4) - -# Esco -width - ButtonIPad - 4 + 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 4)(add)(int 1) - -# Esco -width - ButtonIPad - 5=(str width)(subtract)(str ButtonIPad)(subtract)(int 5) - -# Esco -width - ButtonIPad - 5 + 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 5)(add)(int 1) - -# Tetelestai-Modern -width - ButtonIPad -2=(str width)(subtract)(str ButtonIPad)(subtract)(int 2) - -# Bright -width - ButtonIPad-1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Carved2 -width - ResizerWidth - 1=(str width)(subtract)(str ResizerWidth)(subtract)(int 1) - -# Carved2 -width - ResizerWidth - 2=(str width)(subtract)(str ResizerWidth)(subtract)(int 2) - -# Esco -width - left_width - right_width + 1=(str width)(subtract)(str left_width)(subtract)(str right_width)(add)(int 1) - -# Esco -width - left_width - right_width - 1=(str width)(subtract)(str left_width)(subtract)(str right_width)(subtract)(int 1) - -# Esco -width - mini_icon_width - IconTitleSpacing=(str width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing) - -# Agata, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Black, Correcamins, Crux, Firey 1.0, Firey Dark, Graphite, Maemo, Sandwish, Silverado, Tactile, sky, sky-blue -width - object_width=(str width)(subtract)(str object_width) - -# Esco -width - title_width - IconTitleSpacing=(str width)(subtract)(str title_width)(subtract)(str IconTitleSpacing) - -# Esco -width - title_width - IconTitleSpacing + 25 + 3=(str width)(subtract)(str title_width)(subtract)(str IconTitleSpacing)(add)(int 25)(add)(int 3) - -# Esco -width - title_width - IconTitleSpacing + 25 - 1 + 3=(str width)(subtract)(str title_width)(subtract)(str IconTitleSpacing)(add)(int 25)(subtract)(int 1)(add)(int 3) - -# Esco -width - title_width - IconTitleSpacing - height - 25 + 3=(str width)(subtract)(str title_width)(subtract)(str IconTitleSpacing)(subtract)(str height)(subtract)(int 25)(add)(int 3) - -# Esco -width - title_width - IconTitleSpacing - height - 25 - 1 + 3=(str width)(subtract)(str title_width)(subtract)(str IconTitleSpacing)(subtract)(str height)(subtract)(int 25)(subtract)(int 1)(add)(int 3) - -# Esco -width - title_width - height - (IconTitleSpacing * 2)=(str width)(subtract)(str title_width)(subtract)(str height)(subtract)( (str IconTitleSpacing)(multiply)(int 2) ) - -# Esco -width - title_width - mini_icon_width - (IconTitleSpacing * 2)=(str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)( (str IconTitleSpacing)(multiply)(int 2) ) - -# Esco -width - title_width - mini_icon_width - IconTitleSpacing * 3=(str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing)(multiply)(int 3) - -# Esco -width - title_width - mini_icon_width - IconTitleSpacing * 3 - 18=(str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing)(multiply)(int 3)(subtract)(int 18) - -# Outcrop -width -(width /3.6)=(str width)(subtract)( (str width)(divide)(double 3.6) ) - -# Outcrop -width -(width /3.6) +1=(str width)(subtract)( (str width)(divide)(double 3.6) )(add)(int 1) - -# Outcrop -width -(width /3.6) +2=(str width)(subtract)( (str width)(divide)(double 3.6) )(add)(int 2) - -# Outcrop -width -(width /3.6) -1=(str width)(subtract)( (str width)(divide)(double 3.6) )(subtract)(int 1) - -# Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple -width -7=(str width)(subtract)(int 7) - -# Carved2 -width / 2=(str width)(divide)(int 2) - -# Outcrop -width / 3.4=(str width)(divide)(double 3.4) - -# Outcrop -width / 3.4 -1=(str width)(divide)(double 3.4)(subtract)(int 1) - -# Outcrop -width /2=(str width)(divide)(int 2) - -# Outcrop -width /2+1=(str width)(divide)(int 2)(add)(int 1) - -# Outcrop -width /2-1=(str width)(divide)(int 2)(subtract)(int 1) - -# Outcrop -width /2-2=(str width)(divide)(int 2)(subtract)(int 2) - -# Outcrop -width /3.4 +1=(str width)(divide)(double 3.4)(add)(int 1) - -# Outcrop -width /3.4 +2=(str width)(divide)(double 3.4)(add)(int 2) - -# Mista -width `min` object_width=(str width)(min)(str object_width) - -# Atlanta, Bright -width+1-SpacerWidth/2=(str width)(add)(int 1)(subtract)(str SpacerWidth)(divide)(int 2) - -# Vista Basic -width+2=(str width)(add)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width- ((width-(Bmin`max`height-Bpad*2))/2)=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2)=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2) - 2=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2)*2=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(multiply)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2)*2-1=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(multiply)(int 2)(subtract)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2)*2-3=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(multiply)(int 2)(subtract)(int 3) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2)-1=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 1) - -# Chiro, c2 -width-(ButtonIPad+1)=(str width)(subtract)( (str ButtonIPad)(add)(int 1) ) - -# Chiro, c2 -width-(ButtonIPad+1)*2-1=(str width)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2)(subtract)(int 1) - -# Mista -width-(TitlebarPad*2)=(str width)(subtract)( (str TitlebarPad)(multiply)(int 2) ) - -# 4DWM -width-(left_width+right_width - 1)=(str width)(subtract)( (str left_width)(add)(str right_width)(subtract)(int 1) ) - -# 4DWM -width-(right_width-1)=(str width)(subtract)( (str right_width)(subtract)(int 1) ) - -# 4DWM -width-(right_width-2)=(str width)(subtract)( (str right_width)(subtract)(int 2) ) - -# Maemo -width-(title_width+80)=(str width)(subtract)( (str title_width)(add)(int 80) ) - -# Maemo -width-(title_width+88+8)=(str width)(subtract)( (str title_width)(add)(int 88)(add)(int 8) ) - -# Metabox -width-(width-ButtonIPad)/2-1=(str width)(subtract)( (str width)(subtract)(str ButtonIPad) )(divide)(int 2)(subtract)(int 1) - -# sky, sky-blue -width-0=(str width)(subtract)(int 0) - -# 4DWM, Almond, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, MWM, Maemo, MetaGrip, Metabox, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Shiny, Shiny-Tango, Simple, Simplebox, Sloth , SmoothGNOME, Soft Squares, Tactile, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -width-1=(str width)(subtract)(int 1) - -# 4DWM, Almond, Outcrop, Shiny, Shiny-Tango -width-10=(str width)(subtract)(int 10) - -# Graphite -width-12=(str width)(subtract)(int 12) - -# Almond, Outcrop, pOS -width-15=(str width)(subtract)(int 15) - -# 4DWM, Almond, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Bright, Carved2, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, Gilouche, GiloucheIM, MWM, MetaGrip, Metabox, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, River, Shiny, Shiny-Tango, Silverado, Simple, SmoothGNOME, Tactile, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -width-2=(str width)(subtract)(int 2) - -# 4DWM, Aquarius, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Gilouche, GiloucheIM, Maemo, Outcrop, River, Simple, Simplebox, SmoothGNOME, Tetelestai-Modern, Vista Basic, W2k, c2 -width-3=(str width)(subtract)(int 3) - -# 4DWM, Almond, Amiga, AmigaRelief, Aquarius, Carved2, Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, Maemo, MetaGrip, Outcrop, River, Sandwish, Shiny, Shiny-Tango, SmoothGNOME, Tactile, Tetelestai-Modern, Vista Basic, boxx, c2, pOS -width-4=(str width)(subtract)(int 4) - -# 4DWM, Amiga, AmigaRelief, Aquarius, Bright, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, MWM, River, Shiny-Tango, Sloth , SmoothGNOME, boxx, c2, pOS -width-5=(str width)(subtract)(int 5) - -# 4DWM, Aquarius, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, MWM, MetaGrip, Shiny, Shiny-Tango, Vista Basic, W2k -width-6=(str width)(subtract)(int 6) - -# 4DWM, MWM, MetaGrip, Outcrop, Shiny, Shiny-Tango, pOS -width-7=(str width)(subtract)(int 7) - -# Maemo -width-70=(str width)(subtract)(int 70) - -# Maemo -width-72=(str width)(subtract)(int 72) - -# Almond, Outcrop, W2k, pOS -width-8=(str width)(subtract)(int 8) - -# 4DWM, Almond, Maemo, Outcrop, pOS -width-9=(str width)(subtract)(int 9) - -# Atlanta, Carved2, Chiro, Metabox, Redmond, River, SmoothGNOME, Tetelestai-Modern, c2 -width-ButtonIPad=(str width)(subtract)(str ButtonIPad) - -# Carved2 -width-ButtonIPad + 1=(str width)(subtract)(str ButtonIPad)(add)(int 1) - -# Simple -width-ButtonIPad + 2=(str width)(subtract)(str ButtonIPad)(add)(int 2) - -# Chiro, River, c2 -width-ButtonIPad - 3=(str width)(subtract)(str ButtonIPad)(subtract)(int 3) - -# Carved2, Chiro, River, c2 -width-ButtonIPad*2=(str width)(subtract)(str ButtonIPad)(multiply)(int 2) - -# Simple -width-ButtonIPad*2 + 2=(str width)(subtract)(str ButtonIPad)(multiply)(int 2)(add)(int 2) - -# Carved2 -width-ButtonIPad*2+1=(str width)(subtract)(str ButtonIPad)(multiply)(int 2)(add)(int 1) - -# Atlanta, Chiro, Metabox, Redmond, River, SmoothGNOME, Tetelestai-Modern, c2 -width-ButtonIPad*2-1=(str width)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 1) - -# Bright -width-ButtonIPad*2-2=(str width)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 2) - -# Chiro, River, c2 -width-ButtonIPad*2-5=(str width)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 5) - -# Bright, Chiro, Metabox, River, c2 -width-ButtonIPad-1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Clearbox-look-2 -width-ButtonPad=(str width)(subtract)(str ButtonPad) - -# Clearbox-look-2 -width-ButtonPad*2+1=(str width)(subtract)(str ButtonPad)(multiply)(int 2)(add)(int 1) - -# Clearbox-look-2 -width-ButtonPad*2-1=(str width)(subtract)(str ButtonPad)(multiply)(int 2)(subtract)(int 1) - -# Clearbox-look-2 -width-ButtonPad+1=(str width)(subtract)(str ButtonPad)(add)(int 1) - -# Clearbox-look-2 -width-ButtonPad-1=(str width)(subtract)(str ButtonPad)(subtract)(int 1) - -# Clearbox-look-2 -width-ButtonPad-2=(str width)(subtract)(str ButtonPad)(subtract)(int 2) - -# Clearbox-look-2 -width-PrelightPad=(str width)(subtract)(str PrelightPad) - -# Clearbox-look-2 -width-PrelightPad*2+1=(str width)(subtract)(str PrelightPad)(multiply)(int 2)(add)(int 1) - -# Clearbox-look-2 -width-PrelightPad*2-1=(str width)(subtract)(str PrelightPad)(multiply)(int 2)(subtract)(int 1) - -# Clearbox-look-2 -width-PrelightPad+1=(str width)(subtract)(str PrelightPad)(add)(int 1) - -# Clearbox-look-2 -width-PrelightPad-1=(str width)(subtract)(str PrelightPad)(subtract)(int 1) - -# Clearbox-look-2 -width-PrelightPad-2=(str width)(subtract)(str PrelightPad)(subtract)(int 2) - -# Atlanta, Outcrop, Simple -width-SpacerWidth=(str width)(subtract)(str SpacerWidth) - -# Bright -width-SpacerWidth+2=(str width)(subtract)(str SpacerWidth)(add)(int 2) - -# Bright -width-SpacerWidth+3=(str width)(subtract)(str SpacerWidth)(add)(int 3) - -# Bright -width-SpacerWidth-2=(str width)(subtract)(str SpacerWidth)(subtract)(int 2) - -# Chiro -width-left_width=(str width)(subtract)(str left_width) - -# Atlanta, Bright, Metabox, Simple, SmoothGNOME, TangoDance, Tetelestai-Modern -width-left_width-right_width+1=(str width)(subtract)(str left_width)(subtract)(str right_width)(add)(int 1) - -# Maemo, Mista -width-object_width=(str width)(subtract)(str object_width) - -# 4DWM, Gilouche, GiloucheIM, MWM, SmoothGNOME, Tetelestai-Modern -width-right_width=(str width)(subtract)(str right_width) - -# 4DWM, MWM, Tetelestai-Modern -width-right_width+1=(str width)(subtract)(str right_width)(add)(int 1) - -# 4DWM -width-right_width/2=(str width)(subtract)(str right_width)(divide)(int 2) - -# 4DWM, MWM -width-top_height=(str width)(subtract)(str top_height) - -# 4DWM -width-top_height+1=(str width)(subtract)(str top_height)(add)(int 1) - -# 4DWM -width-top_height+2=(str width)(subtract)(str top_height)(add)(int 2) - -# 4DWM, MWM -width-top_height-1=(str width)(subtract)(str top_height)(subtract)(int 1) - -# Bentham, Clearbox-in, Clearbox-look-2, Clearbox-out, Simplebox, Sloth -width/2=(str width)(divide)(int 2) - -# Bentham -width/2 + width/4 - 1=(str width)(divide)(int 2)(add)(str width)(divide)(int 4)(subtract)(int 1) - -# Bentham -width/2 + width/4 - 2=(str width)(divide)(int 2)(add)(str width)(divide)(int 4)(subtract)(int 2) - -# Bentham -width/2 - width/4 + 1=(str width)(divide)(int 2)(subtract)(str width)(divide)(int 4)(add)(int 1) - -# Clearbox-in, Clearbox-out, MWM, Simplebox -width/2+1=(str width)(divide)(int 2)(add)(int 1) - -# Clearbox-in, Clearbox-out, Metabox, Simplebox -width/2+2=(str width)(divide)(int 2)(add)(int 2) - -# 4DWM, Clearbox-in, Clearbox-out, Simplebox -width/2+3=(str width)(divide)(int 2)(add)(int 3) - -# Clearbox-in, Clearbox-out, Simplebox -width/2+4=(str width)(divide)(int 2)(add)(int 4) - -# Clearbox-in, Clearbox-out, Simplebox -width/2+5=(str width)(divide)(int 2)(add)(int 5) - -# Aquarius -width/2+height/4=(str width)(divide)(int 2)(add)(str height)(divide)(int 4) - -# Aquarius -width/2+height/4+1=(str width)(divide)(int 2)(add)(str height)(divide)(int 4)(add)(int 1) - -# Aquarius -width/2+height/4+2=(str width)(divide)(int 2)(add)(str height)(divide)(int 4)(add)(int 2) - -# Clearbox-look-2 -width/2+width/2-ButtonPad+1=(str width)(divide)(int 2)(add)(str width)(divide)(int 2)(subtract)(str ButtonPad)(add)(int 1) - -# Clearbox-look-2 -width/2+width/2-PrelightPad+1=(str width)(divide)(int 2)(add)(str width)(divide)(int 2)(subtract)(str PrelightPad)(add)(int 1) - -# 4DWM, Clearbox-in, Clearbox-look-2, Clearbox-out, MWM, Simplebox -width/2-1=(str width)(divide)(int 2)(subtract)(int 1) - -# 4DWM, Clearbox-in, Clearbox-out, MWM, Metabox, Simplebox -width/2-2=(str width)(divide)(int 2)(subtract)(int 2) - -# Clearbox-in, Clearbox-out, Simplebox -width/2-3=(str width)(divide)(int 2)(subtract)(int 3) - -# Clearbox-in, Clearbox-out, Simplebox -width/2-4=(str width)(divide)(int 2)(subtract)(int 4) - -# Clearbox-in, Clearbox-out, Simplebox -width/2-5=(str width)(divide)(int 2)(subtract)(int 5) - -# Clearbox-in, Clearbox-out, Simplebox -width/2-6=(str width)(divide)(int 2)(subtract)(int 6) - -# Aquarius -width/2-height/4=(str width)(divide)(int 2)(subtract)(str height)(divide)(int 4) - -# Aquarius -width/2-height/4+1=(str width)(divide)(int 2)(subtract)(str height)(divide)(int 4)(add)(int 1) - -# Aquarius -width/2-height/4+2=(str width)(divide)(int 2)(subtract)(str height)(divide)(int 4)(add)(int 2) - -# Aquarius -width/2-height/6=(str width)(divide)(int 2)(subtract)(str height)(divide)(int 6) - -# Aquarius -width/2-height/6+1=(str width)(divide)(int 2)(subtract)(str height)(divide)(int 6)(add)(int 1) - -# Bentham -width/2-width/8-1=(str width)(divide)(int 2)(subtract)(str width)(divide)(int 8)(subtract)(int 1) - -# Bentham -width/2-width/8-2=(str width)(divide)(int 2)(subtract)(str width)(divide)(int 8)(subtract)(int 2) - -# Bentham -width/4=(str width)(divide)(int 4) - -# Bentham -width/4+2=(str width)(divide)(int 4)(add)(int 2) - -########################### - -# EOF tokentest.ini diff --git a/tools/xlib.py b/tools/xlib.py deleted file mode 100644 index 4a244c4..0000000 --- a/tools/xlib.py +++ /dev/null @@ -1,43 +0,0 @@ -# Very simple Xlib-based client in Python. -# Copyright (c) 2008 Thomas Thurman <tthurman@gnome.org>; GPL 2.0 or later. -# Originally based around example code in python-xlib -# by Peter Liljenberg <petli@ctrl-c.liu.se>. - -import sys - -from Xlib import X -from Xlib.protocol import display -from Xlib.protocol.request import * - -display = display.Display() -screen = display.info.roots[display.default_screen] -window = display.allocate_resource_id() -gc = display.allocate_resource_id() - -CreateWindow(display, None, - depth = screen.root_depth, - wid = window, - parent = screen.root, - x = 100, y = 100, width = 250, height = 250, border_width = 2, - window_class = X.InputOutput, visual = X.CopyFromParent, - background_pixel = screen.white_pixel, - event_mask = (X.ExposureMask | - X.StructureNotifyMask | - X.ButtonPressMask | - X.ButtonReleaseMask | - X.Button1MotionMask), - colormap = X.CopyFromParent) - -CreateGC(display, None, gc, window) - -MapWindow(display, None, window) - -while 1: - event = display.next_event() - - if event.type == X.DestroyNotify: - sys.exit(0) - - print event - - |
