diff options
author | Hubert Figuiere <hub@src.gnome.org> | 2005-06-14 02:25:58 +0000 |
---|---|---|
committer | Hubert Figuiere <hub@src.gnome.org> | 2005-06-14 02:25:58 +0000 |
commit | 01f5b89802686d23c37648040ff13f962d15c79a (patch) | |
tree | b70f275a8b0f265c325cc8beea67cf1e47ffdc45 | |
parent | d9441df224dbc95fdff19947fbbae5f61e4aad5b (diff) | |
download | gtk+-01f5b89802686d23c37648040ff13f962d15c79a.tar.gz |
beginning of a MacOS X port
-rw-r--r-- | configure.in | 66 | ||||
-rw-r--r-- | gdk/Makefile.am | 12 | ||||
-rw-r--r-- | gdk/macosx/Makefile.am | 37 | ||||
-rw-r--r-- | gdk/macosx/gdkdisplay-macosx.h | 71 | ||||
-rw-r--r-- | gdk/macosx/gdkdisplay-macosx.m | 547 | ||||
-rw-r--r-- | gdk/macosx/gdkdrawable-macosx.h | 103 | ||||
-rw-r--r-- | gdk/macosx/gdkevents-macosx.c | 88 | ||||
-rw-r--r-- | gdk/macosx/gdkevents-macosx.m | 2485 | ||||
-rw-r--r-- | gdk/macosx/gdkgc-macosx.m | 1306 | ||||
-rw-r--r-- | gdk/macosx/gdkmacosx.h | 55 | ||||
-rw-r--r-- | gdk/macosx/gdkmain-macosx.c | 42 | ||||
-rw-r--r-- | gdk/macosx/gdknsview-macosx.m | 127 | ||||
-rw-r--r-- | gdk/macosx/gdkpango-macosx.c | 11 | ||||
-rw-r--r-- | gdk/macosx/gdkpixmap-macosx.h | 70 | ||||
-rw-r--r-- | gdk/macosx/gdkprivate-macosx.h | 217 | ||||
-rw-r--r-- | gdk/macosx/gdkscreen-macosx.h | 70 | ||||
-rw-r--r-- | gdk/macosx/gdkscreen-macosx.m | 452 | ||||
-rw-r--r-- | gdk/macosx/gdkwindow-macosx.h | 106 | ||||
-rw-r--r-- | gdk/macosx/gdkwindow-macosx.m | 5540 | ||||
-rw-r--r-- | gtk/Makefile.am | 5 |
20 files changed, 11404 insertions, 6 deletions
diff --git a/configure.in b/configure.in index fcf55c3206..2f2879a5a8 100644 --- a/configure.in +++ b/configure.in @@ -111,6 +111,17 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE") AC_CANONICAL_HOST MATH_LIB=-lm +AC_MSG_CHECKING([for native MacOS X]) +case "$host" in + *-*-darwin*) + os_macosx=yes + ;; + *) + os_macosx=no + ;; +esac +AC_MSG_RESULT([$os_macosx]) + AC_MSG_CHECKING([for native Win32]) case "$host" in *-*-mingw*) @@ -130,6 +141,7 @@ case $host in esac dnl Initialize libtool AC_PROG_CC + AM_DISABLE_STATIC if test "$os_win32" = "yes"; then @@ -166,7 +178,22 @@ esac AC_MSG_RESULT([$platform_win32]) AM_CONDITIONAL(PLATFORM_WIN32, test "$platform_win32" = "yes") + +AC_MSG_CHECKING([for some MacOS X platform]) +case "$host" in + *-*-darwin*|*-*-darwin*) + platform_macosx=yes + ;; + *) + platform_macosx=no + ;; +esac +AC_MSG_RESULT([$platform_macosx]) +AM_CONDITIONAL(PLATFORM_MACOSX, test "$platform_macosx" = "yes") + + AM_CONDITIONAL(OS_WIN32, test "$os_win32" = "yes") +AM_CONDITIONAL(OS_MACOSX, test "$os_macosx" = "yes") AM_CONDITIONAL(OS_UNIX, test "$os_win32" != "yes") AM_CONDITIONAL(OS_LINUX, test "$os_linux" = "yes") @@ -217,18 +244,29 @@ AC_ARG_WITH(ie55, GLIB_AC_DIVERT_BEFORE_HELP([ if test "$platform_win32" = yes; then gdktarget=win32 +elif test "$platform_macosx" = yes; then + gdktarget=macosx else gdktarget=x11 fi ]) +# this because the macro above is broken.... and doesn't work. +if test "$platform_win32" = yes; then + gdktarget=win32 +elif test "$platform_macosx" = yes; then + gdktarget=macosx +else + gdktarget=x11 +fi + AC_ARG_WITH(gdktarget, [ --with-gdktarget=[[x11/linux-fb/win32]] select GDK target [default=$gdktarget]], gdktarget=$with_gdktarget) AC_SUBST(gdktarget) case $gdktarget in - x11|linux-fb|win32) ;; - *) AC_MSG_ERROR([Invalid target for GDK: use x11, linux-fb or win32.]);; + x11|linux-fb|win32|macosx) ;; + *) AC_MSG_ERROR([Invalid target for GDK: use x11, linux-fb, win32 or macosx.]);; esac gdktargetlib=libgdk-$gdktarget-$GTK_API_VERSION.la @@ -331,6 +369,15 @@ if test x"$os_win32" = xyes; then fi fi +# objective-C +OBJC="gcc" +OBJCFLAGS="" +AC_SUBST(OBJC) +AC_SUBST(OBJCFLAGS) +dnl Make Objective-C work with automake 1.7.x +dnl see http://lists.gnu.org/archive/html/automake/2003-05/msg00027.html +AM_CONDITIONAL([am__fastdepOBJC], false) + # Honor aclocal flags ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS" @@ -1343,6 +1390,13 @@ else AM_CONDITIONAL(USE_WIN32, false) fi +if test "x$gdktarget" = "xmacosx"; then + GDK_EXTRA_LIBS="$GDK_EXTRA_LIBS -framework Cocoa -framework ApplicationServices" + AM_CONDITIONAL(USE_MACOSX, true) +else + AM_CONDITIONAL(USE_MACOSX, false) +fi + GDK_PIXBUF_XLIB_PACKAGES= GDK_PIXBUF_XLIB_DEP_LIBS="`$PKG_CONFIG --libs $GDK_PIXBUF_PACKAGES $GDK_PIXBUF_XLIB_PACKAGES` $GDK_PIXBUF_XLIB_EXTRA_LIBS $GDK_PIXBUF_EXTRA_LIBS" GDK_PIXBUF_XLIB_DEP_CFLAGS="`$PKG_CONFIG --cflags gthread-2.0 $GDK_PIXBUF_PACKAGES $GDK_PIXBUF_XLIB_PACKAGES` $GDK_PIXBUF_EXTRA_CFLAGS $GDK_PIXBUF_XLIB_EXTRA_CFLAGS" @@ -1401,6 +1455,8 @@ if test "x$gdktarget" = "xx11"; then if $PKG_CONFIG --exists pangox ; then PANGO_PACKAGES="$PANGO_PACKAGES pangox" fi +elif test "x$gdktarget" = "xmacosx"; then + PANGO_PACKAGES=pangoft2 elif test "x$gdktarget" = "xwin32"; then PANGO_PACKAGES=pangowin32 elif test "x$gdktarget" = "xlinux-fb"; then @@ -1614,6 +1670,10 @@ elif test "x$gdktarget" = "xlinux-fb" ; then gdk_windowing=' #define GDK_WINDOWING_FB #define GDK_NATIVE_WINDOW_POINTER' +elif test "x$gdktarget" = "xmacosx" ; then + gdk_windowing=' +#define GDK_WINDOWING_MACOSX +#define GDK_NATIVE_WINDOW_POINTER' fi if test x$gdk_wchar_h = xyes; then @@ -1673,6 +1733,8 @@ gdk/win32/Makefile gdk/win32/rc/Makefile gdk/win32/rc/gdk.rc gdk/linux-fb/Makefile +gdk/macosx/Makefile +gdk/test/Makefile gtk/Makefile gtk/makefile.msc gtk/gtkversion.h diff --git a/gdk/Makefile.am b/gdk/Makefile.am index 139ea8419b..07cecd586a 100644 --- a/gdk/Makefile.am +++ b/gdk/Makefile.am @@ -1,7 +1,8 @@ ## Makefile.am for gtk+/gdk -SUBDIRS = $(gdktarget) -DIST_SUBDIRS = linux-fb win32 x11 +SUBDIRS = $(gdktarget) test +DIST_SUBDIRS = linux-fb win32 x11 macosx +check_SUBDIRS = test EXTRA_DIST = \ gdkconfig.h.win32 \ @@ -138,6 +139,11 @@ libgdk_linux_fb_2_0_la_LIBADD = linux-fb/libgdk-linux-fb.la $(GDK_DEP_LIBS) \ $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-$(GTK_API_VERSION).la libgdk_linux_fb_2_0_la_LDFLAGS = $(LDADD) +libgdk_macosx_2_0_la_SOURCES = $(common_sources) +libgdk_macosx_2_0_la_LIBADD = macosx/libgdk-macosx.la $(GDK_DEP_LIBS) \ + $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-$(GTK_API_VERSION).la +libgdk_macosx_2_0_la_LDFLAGS = $(LDADD) + libgdk_win32_2_0_la_SOURCES = $(common_sources) gdkkeynames.c libgdk_win32_2_0_la_LIBADD = win32/libgdk-win32.la $(GDK_DEP_LIBS) \ $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-$(GTK_API_VERSION).la @@ -192,7 +198,7 @@ endif lib_LTLIBRARIES = $(gdktargetlib) -EXTRA_LTLIBRARIES = libgdk-x11-2.0.la libgdk-linux-fb-2.0.la libgdk-win32-2.0.la +EXTRA_LTLIBRARIES = libgdk-x11-2.0.la libgdk-linux-fb-2.0.la libgdk-win32-2.0.la libgdk-macosx-2.0.la MAINTAINERCLEANFILES = gdkenumtypes.h stamp-gdkenumtypes.h gdkenumtypes.c \ gdkmarshalers.h gdkmarshalers.c gdkalias.h gdkaliasdef.c diff --git a/gdk/macosx/Makefile.am b/gdk/macosx/Makefile.am new file mode 100644 index 0000000000..7cc646ba6b --- /dev/null +++ b/gdk/macosx/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in + +libgdkincludedir = $(includedir)/gtk-2.0/gdk + +AUTOMAKE_OPTIONS = no-dependencies + +INCLUDES = \ + -DG_LOG_DOMAIN=\"Gdk\" \ + -DGDK_COMPILATION \ + -I$(top_srcdir) \ + -I$(top_srcdir)/gdk \ + -I$(top_builddir)/gdk \ + -DG_DISABLE_DEPRECATED \ + -DGDK_PIXBUF_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + $(GTK_DEBUG_FLAGS) \ + $(GDK_DEP_CFLAGS) + +LDADDS = $(GDK_DEP_LIBS) + +noinst_LTLIBRARIES = libgdk-macosx.la + +libgdk_macosx_la_SOURCES = gdkpango-macosx.c \ + gdkevents-macosx.m \ + gdkdisplay-macosx.m \ + gdkgc-macosx.m \ + gdkmain-macosx.m \ + gdknsview-macosx.m \ + gdkscreen-macosx.m \ + gdkwindow-macosx.m + + +libgdkinclude_HEADERS = + +# We need to include all these C files here since the conditionals +# don't seem to be correctly expanded for the dist files. +EXTRA_DIST = diff --git a/gdk/macosx/gdkdisplay-macosx.h b/gdk/macosx/gdkdisplay-macosx.h new file mode 100644 index 0000000000..ad01410fe2 --- /dev/null +++ b/gdk/macosx/gdkdisplay-macosx.h @@ -0,0 +1,71 @@ +/* + * gdkdisplay-macosx.h + * + * Copyright 2001 Sun Microsystems Inc. + * + * Erwann Chenede <erwann.chenede@sun.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GDK_DISPLAY_MACOSX__ +#define __GDK_DISPLAY_MACOSX__ + +#include <glib.h> +#include <gdk/gdkdisplay.h> +#include <gdk/gdkkeys.h> +#include <gdk/gdkwindow.h> +#include <gdk/gdk.h> /* For gdk_get_program_class() */ + +G_BEGIN_DECLS + +typedef struct _GdkDisplayMacOSX GdkDisplayMacOSX; +typedef struct _GdkDisplayMacOSXClass GdkDisplayMacOSXClass; + +#define GDK_TYPE_DISPLAY_MACOSX (_gdk_display_macosx_get_type()) +#define GDK_DISPLAY_MACOSX(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_DISPLAY_MACOSX, GdkDisplayMacOSX)) +#define GDK_DISPLAY_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DISPLAY_MACOSX, GdkDisplayMacOSXClass)) +#define GDK_IS_DISPLAY_MACOSX(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_DISPLAY_MACOSX)) +#define GDK_IS_DISPLAY_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DISPLAY_MACOSX)) +#define GDK_DISPLAY_MACOSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DISPLAY_MACOSX, GdkDisplayMacOSXClass)) + +typedef enum +{ + GDK_UNKNOWN, + GDK_NO, + GDK_YES +} GdkTristate; + +struct _GdkDisplayMacOSX +{ + GdkDisplay parent_instance; + GdkScreen *default_screen; + GdkScreen **screens; + int num_screens; + /* NSView to GdkWindow pointers */ + GHashTable *nsview_ht; +}; + +struct _GdkDisplayMacOSXClass +{ + GdkDisplayClass parent_class; +}; + +GType _gdk_display_macosx_get_type (void); + +G_END_DECLS + +#endif /* __GDK_DISPLAY_MacOSX__ */ diff --git a/gdk/macosx/gdkdisplay-macosx.m b/gdk/macosx/gdkdisplay-macosx.m new file mode 100644 index 0000000000..079b905b6e --- /dev/null +++ b/gdk/macosx/gdkdisplay-macosx.m @@ -0,0 +1,547 @@ +/* GDK - The GIMP Drawing Kit + * gdkdisplay-macosx.c + * + * Copyright 2001 Sun Microsystems Inc. + * Copyright (C) 2004 Nokia Corporation + * Copyright (C) 2005 Hubert Figuiere + * + * Hubert Figuiere <hub@figuiere.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * derived from GdkDisplay-X11.... + */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include <glib.h> +#include "gdkalias.h" +#include "gdkdisplay.h" +#include "gdkdisplay-macosx.h" +#include "gdkscreen.h" +#include "gdkscreen-macosx.h" +#include "gdkinternals.h" + +#include <Cocoa/Cocoa.h> + +static void gdk_display_macosx_class_init (GdkDisplayMacOSXClass *class); +static void gdk_display_macosx_dispose (GObject *object); +static void gdk_display_macosx_finalize (GObject *object); + + +static gpointer parent_class = NULL; + + +GType +_gdk_display_macosx_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (GdkDisplayMacOSXClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gdk_display_macosx_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GdkDisplayMacOSX), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + }; + + object_type = g_type_register_static (GDK_TYPE_DISPLAY, + "GdkDisplayMacOSX", + &object_info, 0); + } + + return object_type; +} + +static void +gdk_display_macosx_class_init (GdkDisplayMacOSXClass * class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = gdk_display_macosx_dispose; + object_class->finalize = gdk_display_macosx_finalize; + + parent_class = g_type_class_peek_parent (class); +} + + +/** + * gdk_display_open: + * @display_name: the name of the display to open + * @returns: a #GdkDisplay, or %NULL if the display + * could not be opened. + * + * Opens a display. + * + * Since: 2.2 + */ +GdkDisplay * +gdk_display_open (const gchar *display_name) +{ + GdkDisplay *display; + GdkDisplayMacOSX *display_macosx; + GdkWindowAttr attr; + NSArray *screens; + NSScreen *current_screen; + NSScreen *default_screen; + NSEnumerator *iter; + int screen_count, i; + + display = g_object_new (GDK_TYPE_DISPLAY_MACOSX, NULL); + display_macosx = GDK_DISPLAY_MACOSX (display); + + /* initialize the display's screens */ + + screens = [NSScreen screens]; + screen_count = [screens count]; + + display_macosx->screens = g_new (GdkScreen *, screen_count); + default_screen = [NSScreen mainScreen]; + iter = [screens objectEnumerator]; + i = 0; + while (current_screen = [iter nextObject]) { + display_macosx->screens[i] = _gdk_macosx_screen_new (display, current_screen); + if (current_screen == default_screen) { + display_macosx->default_screen = display_macosx->screens[i]; + } + i++; + if(i == screen_count) { + g_warning("screen count changes\n"); + /* FIXME don't leake */ + return NULL; + } + } + display_macosx->num_screens = i; + display_macosx->nsview_ht = NULL; + + /* just make sure we have a NSApplication created */ + [NSApplication sharedApplication]; + + /* FIXME make all of this is OK */ + /* + _gdk_windowing_image_init (display); + _gdk_events_init (display); + _gdk_input_init (display); + _gdk_dnd_init (display); + */ + g_signal_emit_by_name (gdk_display_manager_get(), + "display_opened", display); + + return display; +} + + +/** + * gdk_display_get_name: + * @display: a #GdkDisplay + * + * Gets the name of the display. + * + * Returns: a string representing the display name. This string is owned + * by GDK and should not be modified or freed. + * + * Since: 2.2 + */ +G_CONST_RETURN gchar * +gdk_display_get_name (GdkDisplay * display) +{ + g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); + + return ""; +} + +/** + * gdk_display_get_n_screens: + * @display: a #GdkDisplay + * + * Gets the number of screen managed by the @display. + * + * Returns: number of screens. + * + * Since: 2.2 + */ +gint +gdk_display_get_n_screens (GdkDisplay * display) +{ + g_return_val_if_fail (GDK_IS_DISPLAY (display), 0); + + return [[NSScreen screens] count]; +} + +/** + * gdk_display_get_screen: + * @display: a #GdkDisplay + * @screen_num: the screen number + * + * Returns a screen object for one of the screens of the display. + * + * Returns: the #GdkScreen object + * + * Since: 2.2 + */ +GdkScreen * +gdk_display_get_screen (GdkDisplay * display, gint screen_num) +{ + g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); + g_return_val_if_fail ((GDK_DISPLAY_MACOSX (display)->num_screens) > screen_num, NULL); + + return GDK_DISPLAY_MACOSX (display)->screens[screen_num]; +} + +/** + * gdk_display_get_default_screen: + * @display: a #GdkDisplay + * + * Get the default #GdkScreen for @display. + * + * Returns: the default #GdkScreen object for @display + * + * Since: 2.2 + */ +GdkScreen * +gdk_display_get_default_screen (GdkDisplay * display) +{ + g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); + + return GDK_DISPLAY_MACOSX (display)->default_screen; +} + + +/** + * gdk_display_pointer_ungrab: + * @display: a #GdkDisplay. + * @time_: a timestap (e.g. GDK_CURRENT_TIME). + * + * Release any pointer grab. + * + * Since: 2.2 + */ +void +gdk_display_pointer_ungrab (GdkDisplay *display, + guint32 time) +{ + // FIXME nothing to do +} + +/** + * gdk_display_pointer_is_grabbed: + * @display: a #GdkDisplay + * + * Test if the pointer is grabbed. + * + * Returns: %TRUE if an active X pointer grab is in effect + * + * Since: 2.2 + */ +gboolean +gdk_display_pointer_is_grabbed (GdkDisplay * display) +{ + // FIXME I don't think we have grabs. Maybe should we + // store that state in the GdkDisplay.... + return false; +} + +/** + * gdk_display_keyboard_ungrab: + * @display: a #GdkDisplay. + * @time_: a timestap (e.g #GDK_CURRENT_TIME). + * + * Release any keyboard grab + * + * Since: 2.2 + */ +void +gdk_display_keyboard_ungrab (GdkDisplay *display, + guint32 time) +{ + +} + +/** + * gdk_display_beep: + * @display: a #GdkDisplay + * + * Emits a short beep on @display + * + * Since: 2.2 + */ +void +gdk_display_beep (GdkDisplay * display) +{ + g_return_if_fail (GDK_IS_DISPLAY (display)); + + NSBeep(); +} + +/** + * gdk_display_sync: + * @display: a #GdkDisplay + * + * Flushes any requests queued for the windowing system and waits until all + * requests have been handled. This is often used for making sure that the + * display is synchronized with the current state of the program. Calling + * gdk_display_sync() before gdk_error_trap_pop() makes sure that any errors + * generated from earlier requests are handled before the error trap is + * removed. + * + * This is most useful for X11. On windowing systems where requests are + * handled synchronously, this function will do nothing. + * + * Since: 2.2 + */ +void +gdk_display_sync (GdkDisplay * display) +{ + g_return_if_fail (GDK_IS_DISPLAY (display)); + /* FIXME see if we can do something with CoreGraphics */ +} + +/** + * gdk_display_flush: + * @display: a #GdkDisplay + * + * Flushes any requests queued for the windowing system; this happens automatically + * when the main loop blocks waiting for new events, but if your application + * is drawing without returning control to the main loop, you may need + * to call this function explicitely. A common case where this function + * needs to be called is when an application is executing drawing commands + * from a thread other than the thread where the main loop is running. + * + * This is most useful for X11. On windowing systems where requests are + * handled synchronously, this function will do nothing. + * + * Since: 2.4 + */ +void +gdk_display_flush (GdkDisplay *display) +{ + g_return_if_fail (GDK_IS_DISPLAY (display)); + + /* FIXME see if we can do something with CoreGraphics */ +} + +/** + * gdk_display_get_default_group: + * @display: a #GdkDisplay + * + * Returns the default group leader window for all toplevel windows + * on @display. This window is implicitly created by GDK. + * See gdk_window_set_group(). + * + * Return value: The default group leader window for @display + * + * Since: 2.4 + **/ +GdkWindow *gdk_display_get_default_group (GdkDisplay *display) +{ + g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); + + g_warning ("gdk_display_get_default_group not yet implemented"); + + return NULL; +} + +/** + * gdk_macosx_display_grab: + * @display: a #GdkDisplay + * + * Call XGrabServer() on @display. + * To ungrab the display again, use gdk_macosx_display_ungrab(). + * + * gdk_macosx_display_grab()/gdk_macosx_display_ungrab() calls can be nested. + * + * Since: 2.2 + **/ +void +gdk_macosx_display_grab (GdkDisplay * display) +{ + +} + +/** + * gdk_macosx_display_ungrab: + * @display: a #GdkDisplay + * + * Ungrab @display after it has been grabbed with + * gdk_macosx_display_grab(). + * + * Since: 2.2 + **/ +void +gdk_macosx_display_ungrab (GdkDisplay * display) +{ + +} + +static void +gdk_display_macosx_dispose (GObject *object) +{ + GdkDisplayMacOSX *display_macosx; + gint i; + + display_macosx = GDK_DISPLAY_MACOSX (object); + + for (i = 0; i < display_macosx->num_screens; i++) { + _gdk_screen_close (display_macosx->screens[i]); + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gdk_display_macosx_finalize (GObject *object) +{ + GdkDisplayMacOSX *display_macosx = GDK_DISPLAY_MACOSX (object); + + g_free (display_macosx->screens); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +void +_gdk_windowing_set_default_display (GdkDisplay *display) +{ + /* FIXME */ + g_warning ("_gdk_windowing_set_default_display() not implemented on MacOS X\n"); +} + + + +/** + * gdk_notify_startup_complete: + * + * Indicates to the GUI environment that the application has finished + * loading. If the applications opens windows, this function is + * normally called after opening the application's initial set of + * windows. + * + * GTK+ will call this function automatically after opening the first + * #GtkWindow unless gtk_window_set_auto_startup_notification() is called + * to disable that feature. + * + * Since: 2.2 + **/ +void +gdk_notify_startup_complete (void) +{ + /* FIXME */ + g_warning ("gdk_notify_startup_complete () not implemented on MacOS X\n"); +} + + +/** + * gdk_display_supports_selection_notification: + * @display: a #GdkDisplay + * + * Returns whether #GdkEventOwnerChange events will be + * sent when the owner of a selection changes. + * + * Return value: whether #GdkEventOwnerChange events will + * be sent. + * + * Since: 2.6 + **/ +gboolean +gdk_display_supports_selection_notification (GdkDisplay *display) +{ + /* FIXME I'm not sure we support that */ + + return FALSE; +} + +/** + * gdk_display_request_selection_notification: + * @display: a #GdkDisplay + * @selection: the #GdkAtom naming the selection for which + * ownership change notification is requested + * + * Request #GdkEventOwnerChange events for ownership changes + * of the selection named by the given atom. + * + * Return value: whether #GdkEventOwnerChange events will + * be sent. + * + * Since: 2.6 + **/ +gboolean gdk_display_request_selection_notification (GdkDisplay *display, + GdkAtom selection) + +{ + /* FIXME I'm not sure we support that */ + + return FALSE; +} + +/** + * gdk_display_supports_clipboard_persistence + * @display: a #GdkDisplay + * + * Returns whether the speicifed display supports clipboard + * persistance; i.e. if it's possible to store the clipboard data after an + * application has quit. On MacOSX this checks if a clipboard daemon is + * running. + * + * Returns: %TRUE if the display supports clipboard persistance. + * + * Since: 2.6 + */ +gboolean +gdk_display_supports_clipboard_persistence (GdkDisplay *display) +{ + /* It might make sense to cache this */ + return TRUE; +} + +/** + * gdk_display_store_clipboard + * @display: a #GdkDisplay + * @clipboard_window: a #GdkWindow belonging to the clipboard owner + * @time_: a timestamp + * @targets: an array of targets that should be saved, or %NULL + * if all available targets should be saved. + * @n_targets: length of the @targets array + * + * Issues a request to the clipboard manager to store the + * clipboard data. + * + * Since: 2.6 + */ +void +gdk_display_store_clipboard (GdkDisplay *display, + GdkWindow *clipboard_window, + guint32 time_, + GdkAtom *targets, + gint n_targets) +{ + /* FIXME */ + g_warning ("gdk_display_store_clipboard() not implemented on MacOS X\n"); +} + diff --git a/gdk/macosx/gdkdrawable-macosx.h b/gdk/macosx/gdkdrawable-macosx.h new file mode 100644 index 0000000000..895c60513e --- /dev/null +++ b/gdk/macosx/gdkdrawable-macosx.h @@ -0,0 +1,103 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GDK_DRAWABLE_MACOSX_H__ +#define __GDK_DRAWABLE_MACOSX_H__ + +#include <config.h> +#include <gdk/gdkdrawable.h> + +#include <ApplicationServices/ApplicationServices.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Drawable implementation for MacOSX + */ + +typedef enum +{ + GDK_MACOSX_FORMAT_NONE, + GDK_MACOSX_FORMAT_EXACT_MASK, + GDK_MACOSX_FORMAT_ARGB_MASK, + GDK_MACOSX_FORMAT_ARGB +} GdkMacOSXFormatType; + +typedef struct _GdkDrawableImplMacOSX GdkDrawableImplMacOSX; +typedef struct _GdkDrawableImplMacOSXClass GdkDrawableImplMacOSXClass; + +#define GDK_TYPE_DRAWABLE_IMPL_MACOSX (_gdk_drawable_impl_macosx_get_type ()) +#define GDK_DRAWABLE_IMPL_MACOSX(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_DRAWABLE_IMPL_MACOSX, GdkDrawableImplMacOSX)) +#define GDK_DRAWABLE_IMPL_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DRAWABLE_IMPL_MACOSX, GdkDrawableImplMacOSXClass)) +#define GDK_IS_DRAWABLE_IMPL_MACOSX(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_DRAWABLE_IMPL_MACOSX)) +#define GDK_IS_DRAWABLE_IMPL_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DRAWABLE_IMPL_MACOSX)) +#define GDK_DRAWABLE_IMPL_MACOSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DRAWABLE_IMPL_MACOSX, GdkDrawableImplMacOSXClass)) + + +struct _GdkDrawableImplMacOSX +{ + GdkDrawable parent_instance; + + GdkDrawable *wrapper; + + GdkColormap *colormap; + + CGContextRef cg; +}; + +struct _GdkDrawableImplMacOSXClass +{ + GdkDrawableClass parent_class; +}; + +GType _gdk_drawable_impl_macosx_get_type (void); + +void _gdk_macosx_convert_to_format (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkMacOSXFormatType dest_format, + GdkByteOrder dest_byteorder, + gint width, + gint height); +/* Note that the following take GdkDrawableImplMacOSX, not the wrapper drawable */ +/* +void _gdk_macosx_drawable_draw_xtrapezoids (GdkDrawable *drawable, + GdkGC *gc, + XTrapezoid *xtrapezoids, + int n_trapezoids); +void _gdk_macosx_drawable_draw_xft_glyphs (GdkDrawable *drawable, + GdkGC *gc, + XftFont *xft_font, + XftGlyphSpec *glyphs, + gint n_glyphs); +*/ +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GDK_DRAWABLE_MacOSX_H__ */ diff --git a/gdk/macosx/gdkevents-macosx.c b/gdk/macosx/gdkevents-macosx.c new file mode 100644 index 0000000000..82ee6de833 --- /dev/null +++ b/gdk/macosx/gdkevents-macosx.c @@ -0,0 +1,88 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 2005 Hubert Figuiere + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ +/* + * MacOS X port by Hubert Figuiere + */ + + +#include <config.h> + +#include "gdk.h" +#include "gdkinternals.h" + +#include <Carbon/Carbon.h> + + + +/* + * Currently does nothing + */ +void +gdk_flush (void) +{ + +} + + + +/** + * gdk_event_send_client_message_for_display: + * @display: the #GdkDisplay for the window where the message is to be sent. + * @event: the #GdkEvent to send, which should be a #GdkEventClient. + * @winid: the window to send the client message to. + * + * On X11, sends an X ClientMessage event to a given window. On + * Windows, sends a message registered with the name + * GDK_WIN32_CLIENT_MESSAGE. + * + * This could be used for communicating between different + * applications, though the amount of data is limited to 20 bytes on + * X11, and to just four bytes on Windows. + * + * Returns: non-zero on success. + * + * Since: 2.2 + */ +gboolean +gdk_event_send_client_message_for_display (GdkDisplay *display, + GdkEvent *event, + GdkNativeWindow winid) +{ + /* FIXME */ + g_assert(false); + return false; +} + + +void +_gdk_events_queue (GdkDisplay *display) +{ + while (!_gdk_event_queue_find_first(display)) + { + /* FIXME */ + } +} diff --git a/gdk/macosx/gdkevents-macosx.m b/gdk/macosx/gdkevents-macosx.m new file mode 100644 index 0000000000..94b067e41b --- /dev/null +++ b/gdk/macosx/gdkevents-macosx.m @@ -0,0 +1,2485 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include <config.h> + +#include "gdkalias.h" +#include "gdk.h" +#include "gdkprivate-macosx.h" +#include "gdkinternals.h" +#include "gdkscreen-macosx.h" +#include "gdkdisplay-macosx.h" + +#include <string.h> + +#include <Cocoa/Cocoa.h> + +typedef struct _GdkIOClosure GdkIOClosure; +typedef struct _GdkDisplaySource GdkDisplaySource; +typedef struct _GdkEventTypeMacOSX GdkEventTypeMacOSX; + + +#define GDK_NS_CLIENT_MESSAGE 1 + + +struct _GdkIOClosure +{ + GdkInputFunction function; + GdkInputCondition condition; + GdkDestroyNotify notify; + gpointer data; +}; + +struct _GdkDisplaySource +{ + GSource source; + + GdkDisplay *display; + GPollFD event_poll_fd; +}; + +struct _GdkEventTypeMacOSX +{ + gint base; + gint n_events; +}; + +/* + * Private function declarations + */ +#if 0 +static gint gdk_event_apply_filters (XEvent *xevent, + GdkEvent *event, + GList *filters); +static gboolean gdk_event_translate (GdkDisplay *display, + GdkEvent *event, + XEvent *xevent, + gboolean return_exposes); + +static gboolean gdk_event_prepare (GSource *source, + gint *timeout); +static gboolean gdk_event_check (GSource *source); +static gboolean gdk_event_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data); + +static GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data); + +static GSource *gdk_display_source_new (GdkDisplay *display); +static gboolean gdk_check_xpending (GdkDisplay *display); + +static void gdk_xsettings_watch_cb (Window window, + Bool is_start, + long mask, + void *cb_data); +static void gdk_xsettings_notify_cb (const char *name, + XSettingsAction action, + XSettingsSetting *setting, + void *data); + +/* Private variable declarations + */ + +static GList *display_sources; + +static GSourceFuncs event_funcs = { + gdk_event_prepare, + gdk_event_check, + gdk_event_dispatch, + NULL +}; + +static GSource * +gdk_display_source_new (GdkDisplay *display) +{ + GSource *source = g_source_new (&event_funcs, sizeof (GdkDisplaySource)); + GdkDisplaySource *display_source = (GdkDisplaySource *)source; + + display_source->display = display; + + return source; +} + +static gboolean +gdk_check_xpending (GdkDisplay *display) +{ + return XPending (GDK_DISPLAY_XDISPLAY (display)); +} + +/********************************************* + * Functions for maintaining the event queue * + *********************************************/ + +static void +refcounted_grab_server (Display *xdisplay) +{ + GdkDisplay *display = gdk_macosx_lookup_xdisplay (xdisplay); + + gdk_macosx_display_grab (display); +} + +static void +refcounted_ungrab_server (Display *xdisplay) +{ + GdkDisplay *display = gdk_macosx_lookup_xdisplay (xdisplay); + + gdk_macosx_display_ungrab (display); +} + +void +_gdk_macosx_events_init_screen (GdkScreen *screen) +{ + GdkScreenMacOSX *screen_macosx = GDK_SCREEN_MACOSX (screen); + + /* Keep a flag to avoid extra notifies that we don't need + */ + screen_macosx->xsettings_in_init = TRUE; + screen_macosx->xsettings_client = xsettings_client_new (screen_macosx->xdisplay, + screen_macosx->screen_num, + gdk_xsettings_notify_cb, + gdk_xsettings_watch_cb, + screen); + xsettings_client_set_grab_func (screen_macosx->xsettings_client, + refcounted_grab_server); + xsettings_client_set_ungrab_func (screen_macosx->xsettings_client, + refcounted_ungrab_server); + screen_macosx->xsettings_in_init = FALSE; +} + +void +_gdk_macosx_events_uninit_screen (GdkScreen *screen) +{ + GdkScreenMacOSX *screen_macosx = GDK_SCREEN_MACOSX (screen); + + xsettings_client_destroy (screen_macosx->xsettings_client); + screen_macosx->xsettings_client = NULL; +} + +void +_gdk_events_init (GdkDisplay *display) +{ + GSource *source; + GdkDisplaySource *display_source; + GdkDisplayMacOSX *display_macosx = GDK_DISPLAY_MACOSX (display); + + int connection_number = ConnectionNumber (display_macosx->xdisplay); + GDK_NOTE (MISC, g_message ("connection number: %d", connection_number)); + + + source = display_macosx->event_source = gdk_display_source_new (display); + display_source = (GdkDisplaySource*) source; + g_source_set_priority (source, GDK_PRIORITY_EVENTS); + + display_source->event_poll_fd.fd = connection_number; + display_source->event_poll_fd.events = G_IO_IN; + + g_source_add_poll (source, &display_source->event_poll_fd); + g_source_set_can_recurse (source, TRUE); + g_source_attach (source, NULL); + + display_sources = g_list_prepend (display_sources,display_source); + + gdk_display_add_client_message_filter (display, + gdk_atom_intern ("WM_PROTOCOLS", FALSE), + gdk_wm_protocols_filter, + NULL); +} + + +/** + * gdk_events_pending: + * + * Checks if any events are ready to be processed for any display. + * + * Return value: %TRUE if any events are pending. + **/ +gboolean +gdk_events_pending (void) +{ + GList *tmp_list; + + for (tmp_list = display_sources; tmp_list; tmp_list = tmp_list->next) + { + GdkDisplaySource *tmp_source = tmp_list->data; + GdkDisplay *display = tmp_source->display; + + if (_gdk_event_queue_find_first (display)) + return TRUE; + } + + for (tmp_list = display_sources; tmp_list; tmp_list = tmp_list->next) + { + GdkDisplaySource *tmp_source = tmp_list->data; + GdkDisplay *display = tmp_source->display; + + if (gdk_check_xpending (display)) + return TRUE; + } + + return FALSE; +} + +static Bool +graphics_expose_predicate (Display *display, + XEvent *xevent, + XPointer arg) +{ + if (xevent->xany.window == GDK_DRAWABLE_XID ((GdkDrawable *)arg) && + (xevent->xany.type == GraphicsExpose || + xevent->xany.type == NoExpose)) + return True; + else + return False; +} + +/** + * gdk_event_get_graphics_expose: + * @window: the #GdkWindow to wait for the events for. + * + * Waits for a GraphicsExpose or NoExpose event from the X server. + * This is used in the #GtkText and #GtkCList widgets in GTK+ to make sure any + * GraphicsExpose events are handled before the widget is scrolled. + * + * Return value: a #GdkEventExpose if a GraphicsExpose was received, or %NULL if a + * NoExpose event was received. + **/ +GdkEvent* +gdk_event_get_graphics_expose (GdkWindow *window) +{ + XEvent xevent; + GdkEvent *event; + + g_return_val_if_fail (window != NULL, NULL); + + XIfEvent (GDK_WINDOW_XDISPLAY (window), &xevent, + graphics_expose_predicate, (XPointer) window); + + if (xevent.xany.type == GraphicsExpose) + { + event = gdk_event_new (GDK_NOTHING); + + if (gdk_event_translate (GDK_WINDOW_DISPLAY (window), event, + &xevent, TRUE)) + return event; + else + gdk_event_free (event); + } + + return NULL; +} + +static gint +gdk_event_apply_filters (XEvent *xevent, + GdkEvent *event, + GList *filters) +{ + GList *tmp_list; + GdkFilterReturn result; + + tmp_list = filters; + + while (tmp_list) + { + GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data; + + tmp_list = tmp_list->next; + result = filter->function (xevent, event, filter->data); + if (result != GDK_FILTER_CONTINUE) + return result; + } + + return GDK_FILTER_CONTINUE; +} + +/** + * gdk_display_add_client_message_filter: + * @display: a #GdkDisplay for which this message filter applies + * @message_type: the type of ClientMessage events to receive. + * This will be checked against the @message_type field + * of the XClientMessage event struct. + * @func: the function to call to process the event. + * @data: user data to pass to @func. + * + * Adds a filter to be called when X ClientMessage events are received. + * + * Since: 2.2 + **/ +void +gdk_display_add_client_message_filter (GdkDisplay *display, + GdkAtom message_type, + GdkFilterFunc func, + gpointer data) +{ + GdkClientFilter *filter; + g_return_if_fail (GDK_IS_DISPLAY (display)); + filter = g_new (GdkClientFilter, 1); + + filter->type = message_type; + filter->function = func; + filter->data = data; + + GDK_DISPLAY_MACOSX(display)->client_filters = + g_list_append (GDK_DISPLAY_MacOSX (display)->client_filters, + filter); +} + +/** + * gdk_add_client_message_filter: + * @message_type: the type of ClientMessage events to receive. This will be + * checked against the <structfield>message_type</structfield> field of the + * XClientMessage event struct. + * @func: the function to call to process the event. + * @data: user data to pass to @func. + * + * Adds a filter to the default display to be called when X ClientMessage events + * are received. See gdk_display_add_client_message_filter(). + **/ +void +gdk_add_client_message_filter (GdkAtom message_type, + GdkFilterFunc func, + gpointer data) +{ + gdk_display_add_client_message_filter (gdk_display_get_default (), + message_type, func, data); +} + + +#define HAS_FOCUS(toplevel) \ + ((toplevel)->has_focus || (toplevel)->has_pointer_focus) + +static void +generate_focus_event (GdkWindow *window, + gboolean in) +{ + GdkEvent event; + + event.type = GDK_FOCUS_CHANGE; + event.focus_change.window = window; + event.focus_change.send_event = FALSE; + event.focus_change.in = in; + + gdk_event_put (&event); +} + +static void +set_screen_from_root (GdkDisplay *display, + GdkEvent *event, + Window xrootwin) +{ + GdkScreen *screen; + + screen = _gdk_macosx_display_screen_for_xrootwin (display, xrootwin); + g_assert (screen); + + gdk_event_set_screen (event, screen); +} + +static void +translate_key_event (GdkDisplay *display, + GdkEvent *event, + XEvent *xevent) +{ + GdkKeymap *keymap = gdk_keymap_get_for_display (display); + gunichar c = 0; + guchar buf[7]; + + event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE; + event->key.time = xevent->xkey.time; + + event->key.state = (GdkModifierType) xevent->xkey.state; + event->key.group = _gdk_macosx_get_group_for_state (display, xevent->xkey.state); + event->key.hardware_keycode = xevent->xkey.keycode; + + event->key.keyval = GDK_VoidSymbol; + + gdk_keymap_translate_keyboard_state (keymap, + event->key.hardware_keycode, + event->key.state, + event->key.group, + &event->key.keyval, + NULL, NULL, NULL); + + /* Fill in event->string crudely, since various programs + * depend on it. + */ + event->key.string = NULL; + + if (event->key.keyval != GDK_VoidSymbol) + c = gdk_keyval_to_unicode (event->key.keyval); + + if (c) + { + gsize bytes_written; + gint len; + + /* Apply the control key - Taken from Xlib + */ + if (event->key.state & GDK_CONTROL_MASK) + { + if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F; + else if (c == '2') + { + event->key.string = g_memdup ("\0\0", 2); + event->key.length = 1; + buf[0] = '\0'; + goto out; + } + else if (c >= '3' && c <= '7') c -= ('3' - '\033'); + else if (c == '8') c = '\177'; + else if (c == '/') c = '_' & 0x1F; + } + + len = g_unichar_to_utf8 (c, buf); + buf[len] = '\0'; + + event->key.string = g_locale_from_utf8 (buf, len, + NULL, &bytes_written, + NULL); + if (event->key.string) + event->key.length = bytes_written; + } + else if (event->key.keyval == GDK_Escape) + { + event->key.length = 1; + event->key.string = g_strdup ("\033"); + } + else if (event->key.keyval == GDK_Return || + event->key.keyval == GDK_KP_Enter) + { + event->key.length = 1; + event->key.string = g_strdup ("\r"); + } + + if (!event->key.string) + { + event->key.length = 0; + event->key.string = g_strdup (""); + } + + out: +#ifdef G_ENABLE_DEBUG + if (_gdk_debug_flags & GDK_DEBUG_EVENTS) + { + g_message ("%s:\t\twindow: %ld key: %12s %d", + event->type == GDK_KEY_PRESS ? "key press " : "key release", + xevent->xkey.window, + event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)", + event->key.keyval); + + if (event->key.length > 0) + g_message ("\t\tlength: %4d string: \"%s\"", + event->key.length, buf); + } +#endif /* G_ENABLE_DEBUG */ + return; +} + +/** + * gdk_macosx_register_standard_event_type: + * @display: a #GdkDisplay + * @event_base: first event type code to register + * @n_events: number of event type codes to register + * + * Registers interest in receiving extension events with type codes + * between @event_base and <literal>event_base + n_events - 1</literal>. + * The registered events must have the window field in the same place + * as core X events (this is not the case for e.g. XKB extension events). + * + * If an event type is registered, events of this type will go through + * global and window-specific filters (see gdk_window_add_filter()). + * Unregistered events will only go through global filters. + * GDK may register the events of some X extensions on its own. + * + * This function should only be needed in unusual circumstances, e.g. + * when filtering XInput extension events on the root window. + * + * Since: 2.4 + **/ +void +gdk_macosx_register_standard_event_type (GdkDisplay *display, + gint event_base, + gint n_events) +{ + GdkEventTypeMacOSX *event_type; + GdkDisplayMacOSX *display_macosx; + + display_macosx = GDK_DISPLAY_MACOSX (display); + event_type = g_new (GdkEventTypeMacOSX, 1); + + event_type->base = event_base; + event_type->n_events = n_events; + + display_macosx->event_types = g_slist_prepend (display_macosx->event_types, event_type); +} + +/* Return the window this has to do with, if any, rather + * than the frame or root window that was selecting + * for substructure + */ +static void +get_real_window (GdkDisplay *display, + XEvent *event, + Window *event_window, + Window *filter_window) +{ + /* Core events all have an event->xany.window field, but that's + * not true for extension events + */ + if (event->type >= KeyPress && + event->type <= MappingNotify) + { + *filter_window = event->xany.window; + switch (event->type) + { + case CreateNotify: + *event_window = event->xcreatewindow.window; + break; + case DestroyNotify: + *event_window = event->xdestroywindow.window; + break; + case UnmapNotify: + *event_window = event->xunmap.window; + break; + case MapNotify: + *event_window = event->xmap.window; + break; + case MapRequest: + *event_window = event->xmaprequest.window; + break; + case ReparentNotify: + *event_window = event->xreparent.window; + break; + case ConfigureNotify: + *event_window = event->xconfigure.window; + break; + case ConfigureRequest: + *event_window = event->xconfigurerequest.window; + break; + case GravityNotify: + *event_window = event->xgravity.window; + break; + case CirculateNotify: + *event_window = event->xcirculate.window; + break; + case CirculateRequest: + *event_window = event->xcirculaterequest.window; + break; + default: + *event_window = event->xany.window; + } + } + else + { + GdkDisplayMacOSX *display_macosx = GDK_DISPLAY_MacOSX (display); + GSList *tmp_list; + + for (tmp_list = display_macosx->event_types; + tmp_list; + tmp_list = tmp_list->next) + { + GdkEventTypeMacOSX *event_type = tmp_list->data; + + if (event->type >= event_type->base && + event->type < event_type->base + event_type->n_events) + { + *event_window = event->xany.window; + *filter_window = event->xany.window; + return; + } + } + + *event_window = None; + *filter_window = None; + } +} + +#ifdef G_ENABLE_DEBUG +static const char notify_modes[][19] = { + "NotifyNormal", + "NotifyGrab", + "NotifyUngrab", + "NotifyWhileGrabbed" +}; + +static const char notify_details[][23] = { + "NotifyAncestor", + "NotifyVirtual", + "NotifyInferior", + "NotifyNonlinear", + "NotifyNonlinearVirtual", + "NotifyPointer", + "NotifyPointerRoot", + "NotifyDetailNone" +}; +#endif + +static void +set_user_time (GdkWindow *window, + GdkEvent *event) +{ + g_return_if_fail (event != NULL); + + window = gdk_window_get_toplevel (event->client.window); + g_return_if_fail (GDK_IS_WINDOW (window)); + + /* If an event doesn't have a valid timestamp, we shouldn't use it + * to update the latest user interaction time. + */ + if (gdk_event_get_time (event) != GDK_CURRENT_TIME) + gdk_macosx_window_set_user_time (gdk_window_get_toplevel (window), + gdk_event_get_time (event)); +} + +static gboolean +gdk_event_translate (GdkDisplay *display, + GdkEvent *event, + XEvent *xevent, + gboolean return_exposes) +{ + + GdkWindow *window; + GdkWindowObject *window_private; + GdkWindow *filter_window; + GdkWindowImplMacOSX *window_impl = NULL; + gboolean return_val; + gint xoffset, yoffset; + GdkScreen *screen = NULL; + GdkScreenMacOSX *screen_macosx = NULL; + GdkToplevelMacOSX *toplevel = NULL; + GdkDisplayMacOSX *display_macosx = GDK_DISPLAY_MacOSX (display); + Window xwindow, filter_xwindow; + + return_val = FALSE; + + /* init these, since the done: block uses them */ + window = NULL; + window_private = NULL; + event->any.window = NULL; + + if (_gdk_default_filters) + { + /* Apply global filters */ + GdkFilterReturn result; + result = gdk_event_apply_filters (xevent, event, + _gdk_default_filters); + + if (result != GDK_FILTER_CONTINUE) + { + return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; + goto done; + } + } + + /* Find the GdkWindow that this event relates to. + * Basically this means substructure events + * are reported same as structure events + */ + get_real_window (display, xevent, &xwindow, &filter_xwindow); + + window = gdk_window_lookup_for_display (display, xwindow); + /* We may receive events such as NoExpose/GraphicsExpose + * and ShmCompletion for pixmaps + */ + if (window && !GDK_IS_WINDOW (window)) + window = NULL; + window_private = (GdkWindowObject *) window; + + /* We always run the filters for the window where the event + * is delivered, not the window that it relates to + */ + if (filter_xwindow == xwindow) + filter_window = window; + else + { + filter_window = gdk_window_lookup_for_display (display, filter_xwindow); + if (filter_window && !GDK_IS_WINDOW (filter_window)) + filter_window = NULL; + } + + if (window) + { + screen = GDK_WINDOW_SCREEN (window); + screen_macosx = GDK_SCREEN_MacOSX (screen); + toplevel = _gdk_macosx_window_get_toplevel (window); + } + + if (window != NULL) + { + window_impl = GDK_WINDOW_IMPL_MacOSX (window_private->impl); + + /* Move key events on focus window to the real toplevel, and + * filter out all other events on focus window + */ + if (toplevel && xwindow == toplevel->focus_window) + { + switch (xevent->type) + { + case KeyPress: + case KeyRelease: + xwindow = GDK_WINDOW_XID (window); + xevent->xany.window = xwindow; + break; + default: + return FALSE; + } + } + + g_object_ref (window); + } + + event->any.window = window; + event->any.send_event = xevent->xany.send_event ? TRUE : FALSE; + + if (window_private && GDK_WINDOW_DESTROYED (window)) + { + if (xevent->type != DestroyNotify) + { + return_val = FALSE; + goto done; + } + } + else if (filter_window) + { + /* Apply per-window filters */ + GdkWindowObject *filter_private = (GdkWindowObject *) filter_window; + GdkFilterReturn result; + + if (filter_private->filters) + { + g_object_ref (filter_window); + + result = gdk_event_apply_filters (xevent, event, + filter_private->filters); + + g_object_unref (filter_window); + + if (result != GDK_FILTER_CONTINUE) + { + return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; + goto done; + } + } + } + + if (screen_macosx && screen_macosx->wmspec_check_window != None && + xwindow == screen_macosx->wmspec_check_window) + { + if (xevent->type == DestroyNotify) + { + screen_macosx->wmspec_check_window = None; + g_free (screen_macosx->window_manager_name); + screen_macosx->window_manager_name = g_strdup ("unknown"); + + /* careful, reentrancy */ + _gdk_macosx_screen_window_manager_changed (GDK_SCREEN (screen_macosx)); + } + + /* Eat events on this window unless someone had wrapped + * it as a foreign window + */ + if (window == NULL) + { + return_val = FALSE; + goto done; + } + } + + if (window && + (xevent->xany.type == MotionNotify || + xevent->xany.type == ButtonRelease)) + { + if (_gdk_moveresize_handle_event (xevent)) + { + return_val = FALSE; + goto done; + } + } + + /* We do a "manual" conversion of the XEvent to a + * GdkEvent. The structures are mostly the same so + * the conversion is fairly straightforward. We also + * optionally print debugging info regarding events + * received. + */ + + return_val = TRUE; + + if (window) + { + _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset); + } + else + { + xoffset = 0; + yoffset = 0; + } + + switch (xevent->type) + { + case KeyPress: + if (window_private == NULL) + { + return_val = FALSE; + break; + } + translate_key_event (display, event, xevent); + set_user_time (window, event); + break; + + case KeyRelease: + if (window_private == NULL) + { + return_val = FALSE; + break; + } + + /* Emulate detectable auto-repeat by checking to see + * if the next event is a key press with the same + * keycode and timestamp, and if so, ignoring the event. + */ + + if (!display_macosx->have_xkb_autorepeat && XPending (xevent->xkey.display)) + { + XEvent next_event; + + XPeekEvent (xevent->xkey.display, &next_event); + + if (next_event.type == KeyPress && + next_event.xkey.keycode == xevent->xkey.keycode && + next_event.xkey.time == xevent->xkey.time) + { + return_val = FALSE; + break; + } + } + + translate_key_event (display, event, xevent); + break; + + case ButtonPress: + GDK_NOTE (EVENTS, + g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d", + xevent->xbutton.window, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button)); + + if (window_private == NULL || + ((window_private->extension_events != 0) && + display_macosx->input_ignore_core)) + { + return_val = FALSE; + break; + } + + /* If we get a ButtonPress event where the button is 4 or 5, + it's a Scroll event */ + switch (xevent->xbutton.button) + { + case 4: /* up */ + case 5: /* down */ + case 6: /* left */ + case 7: /* right */ + event->scroll.type = GDK_SCROLL; + + if (xevent->xbutton.button == 4) + event->scroll.direction = GDK_SCROLL_UP; + else if (xevent->xbutton.button == 5) + event->scroll.direction = GDK_SCROLL_DOWN; + else if (xevent->xbutton.button == 6) + event->scroll.direction = GDK_SCROLL_LEFT; + else + event->scroll.direction = GDK_SCROLL_RIGHT; + + event->scroll.window = window; + event->scroll.time = xevent->xbutton.time; + event->scroll.x = xevent->xbutton.x + xoffset; + event->scroll.y = xevent->xbutton.y + yoffset; + event->scroll.x_root = (gfloat)xevent->xbutton.x_root; + event->scroll.y_root = (gfloat)xevent->xbutton.y_root; + event->scroll.state = (GdkModifierType) xevent->xbutton.state; + event->scroll.device = display->core_pointer; + + set_screen_from_root (display, event, xevent->xbutton.root); + + break; + + default: + event->button.type = GDK_BUTTON_PRESS; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x + xoffset; + event->button.y = xevent->xbutton.y + yoffset; + event->button.x_root = (gfloat)xevent->xbutton.x_root; + event->button.y_root = (gfloat)xevent->xbutton.y_root; + event->button.axes = NULL; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.device = display->core_pointer; + + set_screen_from_root (display, event, xevent->xbutton.root); + + _gdk_event_button_generate (display, event); + break; + } + + set_user_time (window, event); + break; + + case ButtonRelease: + GDK_NOTE (EVENTS, + g_message ("button release:\twindow: %ld x,y: %d %d button: %d", + xevent->xbutton.window, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button)); + + if (window_private == NULL || + ((window_private->extension_events != 0) && + display_macosx->input_ignore_core)) + { + return_val = FALSE; + break; + } + + /* We treat button presses as scroll wheel events, so ignore the release */ + if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 || + xevent->xbutton.button == 6 || xevent->xbutton.button ==7) + { + return_val = FALSE; + break; + } + + event->button.type = GDK_BUTTON_RELEASE; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x + xoffset; + event->button.y = xevent->xbutton.y + yoffset; + event->button.x_root = (gfloat)xevent->xbutton.x_root; + event->button.y_root = (gfloat)xevent->xbutton.y_root; + event->button.axes = NULL; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.device = display->core_pointer; + + set_screen_from_root (display, event, xevent->xbutton.root); + + break; + + case MotionNotify: + GDK_NOTE (EVENTS, + g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s", + xevent->xmotion.window, + xevent->xmotion.x, xevent->xmotion.y, + (xevent->xmotion.is_hint) ? "true" : "false")); + + if (window_private == NULL || + ((window_private->extension_events != 0) && + display_macosx->input_ignore_core)) + { + return_val = FALSE; + break; + } + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = window; + event->motion.time = xevent->xmotion.time; + event->motion.x = xevent->xmotion.x + xoffset; + event->motion.y = xevent->xmotion.y + yoffset; + event->motion.x_root = (gfloat)xevent->xmotion.x_root; + event->motion.y_root = (gfloat)xevent->xmotion.y_root; + event->motion.axes = NULL; + event->motion.state = (GdkModifierType) xevent->xmotion.state; + event->motion.is_hint = xevent->xmotion.is_hint; + event->motion.device = display->core_pointer; + + set_screen_from_root (display, event, xevent->xmotion.root); + + break; + + case EnterNotify: + GDK_NOTE (EVENTS, + g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld", + xevent->xcrossing.window, + xevent->xcrossing.detail, + xevent->xcrossing.subwindow)); + + if (window_private == NULL) + { + return_val = FALSE; + break; + } + + /* Handle focusing (in the case where no window manager is running */ + if (toplevel && + xevent->xcrossing.detail != NotifyInferior && + xevent->xcrossing.focus && !toplevel->has_focus_window) + { + gboolean had_focus = HAS_FOCUS (toplevel); + + toplevel->has_pointer_focus = TRUE; + + if (HAS_FOCUS (toplevel) != had_focus) + generate_focus_event (window, TRUE); + } + + /* Tell XInput stuff about it if appropriate */ + if (window_private && + !GDK_WINDOW_DESTROYED (window) && + window_private->extension_events != 0) + _gdk_input_enter_event (&xevent->xcrossing, window); + + event->crossing.type = GDK_ENTER_NOTIFY; + event->crossing.window = window; + + /* If the subwindow field of the XEvent is non-NULL, then + * lookup the corresponding GdkWindow. + */ + if (xevent->xcrossing.subwindow != None) + event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow); + else + event->crossing.subwindow = NULL; + + event->crossing.time = xevent->xcrossing.time; + event->crossing.x = xevent->xcrossing.x + xoffset; + event->crossing.y = xevent->xcrossing.y + yoffset; + event->crossing.x_root = xevent->xcrossing.x_root; + event->crossing.y_root = xevent->xcrossing.y_root; + + set_screen_from_root (display, event, xevent->xcrossing.root); + + /* Translate the crossing mode into Gdk terms. + */ + switch (xevent->xcrossing.mode) + { + case NotifyNormal: + event->crossing.mode = GDK_CROSSING_NORMAL; + break; + case NotifyGrab: + event->crossing.mode = GDK_CROSSING_GRAB; + break; + case NotifyUngrab: + event->crossing.mode = GDK_CROSSING_UNGRAB; + break; + }; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + + event->crossing.focus = xevent->xcrossing.focus; + event->crossing.state = xevent->xcrossing.state; + + break; + + case LeaveNotify: + GDK_NOTE (EVENTS, + g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld", + xevent->xcrossing.window, + xevent->xcrossing.detail, xevent->xcrossing.subwindow)); + + if (window_private == NULL) + { + return_val = FALSE; + break; + } + + /* Handle focusing (in the case where no window manager is running */ + if (toplevel && + xevent->xcrossing.detail != NotifyInferior && + xevent->xcrossing.focus && !toplevel->has_focus_window) + { + gboolean had_focus = HAS_FOCUS (toplevel); + + toplevel->has_pointer_focus = FALSE; + + if (HAS_FOCUS (toplevel) != had_focus) + generate_focus_event (window, FALSE); + } + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = window; + + /* If the subwindow field of the XEvent is non-NULL, then + * lookup the corresponding GdkWindow. + */ + if (xevent->xcrossing.subwindow != None) + event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow); + else + event->crossing.subwindow = NULL; + + event->crossing.time = xevent->xcrossing.time; + event->crossing.x = xevent->xcrossing.x + xoffset; + event->crossing.y = xevent->xcrossing.y + yoffset; + event->crossing.x_root = xevent->xcrossing.x_root; + event->crossing.y_root = xevent->xcrossing.y_root; + + set_screen_from_root (display, event, xevent->xcrossing.root); + + /* Translate the crossing mode into Gdk terms. + */ + switch (xevent->xcrossing.mode) + { + case NotifyNormal: + event->crossing.mode = GDK_CROSSING_NORMAL; + break; + case NotifyGrab: + event->crossing.mode = GDK_CROSSING_GRAB; + break; + case NotifyUngrab: + event->crossing.mode = GDK_CROSSING_UNGRAB; + break; + }; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + + event->crossing.focus = xevent->xcrossing.focus; + event->crossing.state = xevent->xcrossing.state; + + break; + + /* We only care about focus events that indicate that _this_ + * window (not a ancestor or child) got or lost the focus + */ + case FocusIn: + GDK_NOTE (EVENTS, + g_message ("focus in:\t\twindow: %ld, detail: %s, mode: %s", + xevent->xfocus.window, + notify_details[xevent->xfocus.detail], + notify_modes[xevent->xfocus.mode])); + + if (toplevel) + { + gboolean had_focus = HAS_FOCUS (toplevel); + + switch (xevent->xfocus.detail) + { + case NotifyAncestor: + case NotifyNonlinear: + case NotifyVirtual: + case NotifyNonlinearVirtual: + toplevel->has_focus_window = TRUE; + /* We pretend that the focus moves to the grab + * window, so we pay attention to NotifyGrab + * NotifyUngrab, and ignore NotifyWhileGrabbed + */ + if (xevent->xfocus.mode != NotifyWhileGrabbed) + toplevel->has_focus = TRUE; + break; + case NotifyPointer: + /* The X server sends NotifyPointer/NotifyGrab, + * but the pointer focus is ignored while a + * grab is in effect + */ + if (xevent->xfocus.mode != NotifyGrab) + toplevel->has_pointer_focus = TRUE; + break; + case NotifyInferior: + case NotifyPointerRoot: + case NotifyDetailNone: + break; + } + + if (HAS_FOCUS (toplevel) != had_focus) + generate_focus_event (window, TRUE); + } + break; + case FocusOut: + GDK_NOTE (EVENTS, + g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s", + xevent->xfocus.window, + notify_details[xevent->xfocus.detail], + notify_modes[xevent->xfocus.mode])); + + if (toplevel) + { + gboolean had_focus = HAS_FOCUS (toplevel); + + switch (xevent->xfocus.detail) + { + case NotifyAncestor: + case NotifyNonlinear: + case NotifyVirtual: + case NotifyNonlinearVirtual: + toplevel->has_focus_window = FALSE; + if (xevent->xfocus.mode != NotifyWhileGrabbed) + toplevel->has_focus = FALSE; + break; + case NotifyPointer: + if (xevent->xfocus.mode != NotifyUngrab) + toplevel->has_pointer_focus = FALSE; + break; + case NotifyInferior: + case NotifyPointerRoot: + case NotifyDetailNone: + break; + } + + if (HAS_FOCUS (toplevel) != had_focus) + generate_focus_event (window, FALSE); + } + break; + +#if 0 + /* gdk_keyboard_grab() causes following events. These events confuse + * the XIM focus, so ignore them. + */ + if (xevent->xfocus.mode == NotifyGrab || + xevent->xfocus.mode == NotifyUngrab) + break; +#endif + + case KeymapNotify: + GDK_NOTE (EVENTS, + g_message ("keymap notify")); + + /* Not currently handled */ + return_val = FALSE; + break; + + case Expose: + GDK_NOTE (EVENTS, + g_message ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d%s", + xevent->xexpose.window, xevent->xexpose.count, + xevent->xexpose.x, xevent->xexpose.y, + xevent->xexpose.width, xevent->xexpose.height, + event->any.send_event ? " (send)" : "")); + + if (window_private == NULL) + { + return_val = FALSE; + break; + } + + { + GdkRectangle expose_rect; + + expose_rect.x = xevent->xexpose.x + xoffset; + expose_rect.y = xevent->xexpose.y + yoffset; + expose_rect.width = xevent->xexpose.width; + expose_rect.height = xevent->xexpose.height; + + if (return_exposes) + { + event->expose.type = GDK_EXPOSE; + event->expose.area = expose_rect; + event->expose.region = gdk_region_rectangle (&expose_rect); + event->expose.window = window; + event->expose.count = xevent->xexpose.count; + + return_val = TRUE; + } + else + { + _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect); + return_val = FALSE; + } + + return_val = FALSE; + } + + break; + + case GraphicsExpose: + { + GdkRectangle expose_rect; + + GDK_NOTE (EVENTS, + g_message ("graphics expose:\tdrawable: %ld", + xevent->xgraphicsexpose.drawable)); + + if (window_private == NULL) + { + return_val = FALSE; + break; + } + + expose_rect.x = xevent->xgraphicsexpose.x + xoffset; + expose_rect.y = xevent->xgraphicsexpose.y + yoffset; + expose_rect.width = xevent->xgraphicsexpose.width; + expose_rect.height = xevent->xgraphicsexpose.height; + + if (return_exposes) + { + event->expose.type = GDK_EXPOSE; + event->expose.area = expose_rect; + event->expose.region = gdk_region_rectangle (&expose_rect); + event->expose.window = window; + event->expose.count = xevent->xgraphicsexpose.count; + + return_val = TRUE; + } + else + { + _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect); + + return_val = FALSE; + } + + } + break; + + case NoExpose: + GDK_NOTE (EVENTS, + g_message ("no expose:\t\tdrawable: %ld", + xevent->xnoexpose.drawable)); + + event->no_expose.type = GDK_NO_EXPOSE; + event->no_expose.window = window; + + break; + + case VisibilityNotify: +#ifdef G_ENABLE_DEBUG + if (_gdk_debug_flags & GDK_DEBUG_EVENTS) + switch (xevent->xvisibility.state) + { + case VisibilityFullyObscured: + g_message ("visibility notify:\twindow: %ld none", + xevent->xvisibility.window); + break; + case VisibilityPartiallyObscured: + g_message ("visibility notify:\twindow: %ld partial", + xevent->xvisibility.window); + break; + case VisibilityUnobscured: + g_message ("visibility notify:\twindow: %ld full", + xevent->xvisibility.window); + break; + } +#endif /* G_ENABLE_DEBUG */ + + if (window_private == NULL) + { + return_val = FALSE; + break; + } + + event->visibility.type = GDK_VISIBILITY_NOTIFY; + event->visibility.window = window; + + switch (xevent->xvisibility.state) + { + case VisibilityFullyObscured: + event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED; + break; + + case VisibilityPartiallyObscured: + event->visibility.state = GDK_VISIBILITY_PARTIAL; + break; + + case VisibilityUnobscured: + event->visibility.state = GDK_VISIBILITY_UNOBSCURED; + break; + } + + break; + + case CreateNotify: + GDK_NOTE (EVENTS, + g_message ("create notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d parent: %ld ovr: %d", + xevent->xcreatewindow.window, + xevent->xcreatewindow.x, + xevent->xcreatewindow.y, + xevent->xcreatewindow.width, + xevent->xcreatewindow.height, + xevent->xcreatewindow.border_width, + xevent->xcreatewindow.parent, + xevent->xcreatewindow.override_redirect)); + /* not really handled */ + break; + + case DestroyNotify: + GDK_NOTE (EVENTS, + g_message ("destroy notify:\twindow: %ld", + xevent->xdestroywindow.window)); + + /* Ignore DestroyNotify from SubstructureNotifyMask */ + if (xevent->xdestroywindow.window == xevent->xdestroywindow.event) + { + event->any.type = GDK_DESTROY; + event->any.window = window; + + return_val = window_private && !GDK_WINDOW_DESTROYED (window); + + if (window && GDK_WINDOW_XID (window) != screen_macosx->xroot_window) + gdk_window_destroy_notify (window); + } + else + return_val = FALSE; + + break; + + case UnmapNotify: + GDK_NOTE (EVENTS, + g_message ("unmap notify:\t\twindow: %ld", + xevent->xmap.window)); + + event->any.type = GDK_UNMAP; + event->any.window = window; + + /* If we are shown (not withdrawn) and get an unmap, it means we + * were iconified in the X sense. If we are withdrawn, and get + * an unmap, it means we hid the window ourselves, so we + * will have already flipped the iconified bit off. + */ + if (window) + { + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_ICONIFIED); + + _gdk_xgrab_check_unmap (window, xevent->xany.serial); + } + + break; + + case MapNotify: + GDK_NOTE (EVENTS, + g_message ("map notify:\t\twindow: %ld", + xevent->xmap.window)); + + event->any.type = GDK_MAP; + event->any.window = window; + + /* Unset iconified if it was set */ + if (window && (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED)) + gdk_synthesize_window_state (window, + GDK_WINDOW_STATE_ICONIFIED, + 0); + + break; + + case ReparentNotify: + GDK_NOTE (EVENTS, + g_message ("reparent notify:\twindow: %ld x,y: %d %d parent: %ld ovr: %d", + xevent->xreparent.window, + xevent->xreparent.x, + xevent->xreparent.y, + xevent->xreparent.parent, + xevent->xreparent.override_redirect)); + + /* Not currently handled */ + return_val = FALSE; + break; + + case ConfigureNotify: + GDK_NOTE (EVENTS, + g_message ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d above: %ld ovr: %d%s", + xevent->xconfigure.window, + xevent->xconfigure.x, + xevent->xconfigure.y, + xevent->xconfigure.width, + xevent->xconfigure.height, + xevent->xconfigure.border_width, + xevent->xconfigure.above, + xevent->xconfigure.override_redirect, + !window + ? " (discarding)" + : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD + ? " (discarding child)" + : xevent->xconfigure.event != xevent->xconfigure.window + ? " (discarding substructure)" + : "")); + if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT) + _gdk_macosx_screen_size_changed (screen, xevent); + + if (window && + xevent->xconfigure.event == xevent->xconfigure.window && + !GDK_WINDOW_DESTROYED (window) && + (window_private->extension_events != 0)) + _gdk_input_configure_event (&xevent->xconfigure, window); + +#ifdef HAVE_XSYNC + if (toplevel && display_macosx->use_sync && !XSyncValueIsZero (toplevel->pending_counter_value)) + { + toplevel->current_counter_value = toplevel->pending_counter_value; + XSyncIntToValue (&toplevel->pending_counter_value, 0); + } +#endif + + if (!window || + xevent->xconfigure.event != xevent->xconfigure.window || + GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD || + GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT) + return_val = FALSE; + else + { + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + event->configure.width = xevent->xconfigure.width; + event->configure.height = xevent->xconfigure.height; + + if (!xevent->xconfigure.send_event && + !xevent->xconfigure.override_redirect && + !GDK_WINDOW_DESTROYED (window)) + { + gint tx = 0; + gint ty = 0; + Window child_window = 0; + + gdk_error_trap_push (); + if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + screen_macosx->xroot_window, + 0, 0, + &tx, &ty, + &child_window)) + { + event->configure.x = tx; + event->configure.y = ty; + } + gdk_error_trap_pop (); + } + else + { + event->configure.x = xevent->xconfigure.x; + event->configure.y = xevent->xconfigure.y; + } + window_private->x = event->configure.x; + window_private->y = event->configure.y; + window_impl->width = xevent->xconfigure.width; + window_impl->height = xevent->xconfigure.height; + if (window_private->resize_count >= 1) + { + window_private->resize_count -= 1; + + if (window_private->resize_count == 0) + _gdk_moveresize_configure_done (display, window); + } + } + break; + + case PropertyNotify: + GDK_NOTE (EVENTS, + g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s", + xevent->xproperty.window, + xevent->xproperty.atom, + "\"", + gdk_macosx_get_xatom_name_for_display (display, xevent->xproperty.atom), + "\"")); + + if (window_private == NULL) + { + return_val = FALSE; + break; + } + + /* We compare with the serial of the last time we mapped the + * window to avoid refetching properties that we set ourselves + */ + if (toplevel && + xevent->xproperty.serial >= toplevel->map_serial) + { + if (xevent->xproperty.atom == gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_STATE")) + gdk_check_wm_state_changed (window); + + if (xevent->xproperty.atom == gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP")) + gdk_check_wm_desktop_changed (window); + } + + if (window_private->event_mask & GDK_PROPERTY_CHANGE_MASK) + { + event->property.type = GDK_PROPERTY_NOTIFY; + event->property.window = window; + event->property.atom = gdk_macosx_xatom_to_atom_for_display (display, xevent->xproperty.atom); + event->property.time = xevent->xproperty.time; + event->property.state = xevent->xproperty.state; + } + else + return_val = FALSE; + + break; + + case SelectionClear: + GDK_NOTE (EVENTS, + g_message ("selection clear:\twindow: %ld", + xevent->xproperty.window)); + + if (_gdk_selection_filter_clear_event (&xevent->xselectionclear)) + { + event->selection.type = GDK_SELECTION_CLEAR; + event->selection.window = window; + event->selection.selection = gdk_macosx_xatom_to_atom_for_display (display, xevent->xselectionclear.selection); + event->selection.time = xevent->xselectionclear.time; + } + else + return_val = FALSE; + + break; + + case SelectionRequest: + GDK_NOTE (EVENTS, + g_message ("selection request:\twindow: %ld", + xevent->xproperty.window)); + + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = gdk_macosx_xatom_to_atom_for_display (display, xevent->xselectionrequest.selection); + event->selection.target = gdk_macosx_xatom_to_atom_for_display (display, xevent->xselectionrequest.target); + event->selection.property = gdk_macosx_xatom_to_atom_for_display (display, xevent->xselectionrequest.property); + event->selection.requestor = xevent->xselectionrequest.requestor; + event->selection.time = xevent->xselectionrequest.time; + + break; + + case SelectionNotify: + GDK_NOTE (EVENTS, + g_message ("selection notify:\twindow: %ld", + xevent->xproperty.window)); + + + event->selection.type = GDK_SELECTION_NOTIFY; + event->selection.window = window; + event->selection.selection = gdk_macosx_xatom_to_atom_for_display (display, xevent->xselection.selection); + event->selection.target = gdk_macosx_xatom_to_atom_for_display (display, xevent->xselection.target); + event->selection.property = gdk_macosx_xatom_to_atom_for_display (display, xevent->xselection.property); + event->selection.time = xevent->xselection.time; + + break; + + case ColormapNotify: + GDK_NOTE (EVENTS, + g_message ("colormap notify:\twindow: %ld", + xevent->xcolormap.window)); + + /* Not currently handled */ + return_val = FALSE; + break; + + case ClientMessage: + { + GList *tmp_list; + GdkFilterReturn result = GDK_FILTER_CONTINUE; + GdkAtom message_type = gdk_macosx_xatom_to_atom_for_display (display, xevent->xclient.message_type); + + GDK_NOTE (EVENTS, + g_message ("client message:\twindow: %ld", + xevent->xclient.window)); + + tmp_list = display_macosx->client_filters; + while (tmp_list) + { + GdkClientFilter *filter = tmp_list->data; + tmp_list = tmp_list->next; + + if (filter->type == message_type) + { + result = (*filter->function) (xevent, event, filter->data); + if (result != GDK_FILTER_CONTINUE) + break; + } + } + + switch (result) + { + case GDK_FILTER_REMOVE: + return_val = FALSE; + break; + case GDK_FILTER_TRANSLATE: + return_val = TRUE; + break; + case GDK_FILTER_CONTINUE: + /* Send unknown ClientMessage's on to Gtk for it to use */ + if (window_private == NULL) + { + return_val = FALSE; + } + else + { + event->client.type = GDK_CLIENT_EVENT; + event->client.window = window; + event->client.message_type = message_type; + event->client.data_format = xevent->xclient.format; + memcpy(&event->client.data, &xevent->xclient.data, + sizeof(event->client.data)); + } + break; + } + } + + break; + + case MappingNotify: + GDK_NOTE (EVENTS, + g_message ("mapping notify")); + + /* Let XLib know that there is a new keyboard mapping. + */ + XRefreshKeyboardMapping (&xevent->xmapping); + _gdk_keymap_keys_changed (display); + return_val = FALSE; + break; + + default: +#ifdef HAVE_XKB + if (xevent->type == display_macosx->xkb_event_type) + { + XkbEvent *xkb_event = (XkbEvent *)xevent; + + switch (xkb_event->any.xkb_type) + { + case XkbNewKeyboardNotify: + case XkbMapNotify: + _gdk_keymap_keys_changed (display); + + return_val = FALSE; + break; + + case XkbStateNotify: + _gdk_keymap_state_changed (display); + break; + } + } + else +#endif +#ifdef HAVE_XFIXES + if (xevent->type - display_macosx->xfixes_event_base == XFixesSelectionNotify) + { + XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)xevent; + event->owner_change.type = GDK_OWNER_CHANGE; + event->owner_change.window = window; + event->owner_change.owner = selection_notify->owner; + event->owner_change.reason = selection_notify->subtype; + event->owner_change.selection = + gdk_macosx_xatom_to_atom_for_display (display, + selection_notify->selection); + event->owner_change.time = selection_notify->timestamp; + event->owner_change.selection_time = selection_notify->selection_timestamp; + + return_val = TRUE; + } + else +#endif + { + /* something else - (e.g., a Xinput event) */ + + if (window_private && + !GDK_WINDOW_DESTROYED (window_private) && + (window_private->extension_events != 0)) + return_val = _gdk_input_other_event(event, xevent, window); + else + return_val = FALSE; + + break; + } + } + + done: + if (return_val) + { + if (event->any.window) + g_object_ref (event->any.window); + if (((event->any.type == GDK_ENTER_NOTIFY) || + (event->any.type == GDK_LEAVE_NOTIFY)) && + (event->crossing.subwindow != NULL)) + g_object_ref (event->crossing.subwindow); + } + else + { + /* Mark this event as having no resources to be freed */ + event->any.window = NULL; + event->any.type = GDK_NOTHING; + } + + if (window) + g_object_unref (window); + + return return_val; +} + +static GdkFilterReturn +gdk_wm_protocols_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data) +{ + XEvent *xevent = (XEvent *)xev; + GdkWindow *win = event->any.window; + GdkDisplay *display; + Atom atom; + + if (!win) + return GDK_FILTER_REMOVE; + + display = GDK_WINDOW_DISPLAY (win); + atom = (Atom)xevent->xclient.data.l[0]; + + if (atom == gdk_macosx_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW")) + { + /* The delete window request specifies a window + * to delete. We don't actually destroy the + * window because "it is only a request". (The + * window might contain vital data that the + * program does not want destroyed). Instead + * the event is passed along to the program, + * which should then destroy the window. + */ + GDK_NOTE (EVENTS, + g_message ("delete window:\t\twindow: %ld", + xevent->xclient.window)); + + event->any.type = GDK_DELETE; + + gdk_macosx_window_set_user_time (win, xevent->xclient.data.l[1]); + + return GDK_FILTER_TRANSLATE; + } + else if (atom == gdk_macosx_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS")) + { + GdkToplevelMacOSX *toplevel = _gdk_macosx_window_get_toplevel (event->any.window); + GdkWindowObject *private = (GdkWindowObject *)win; + + /* There is no way of knowing reliably whether we are viewable; + * _gdk_macosx_set_input_focus_safe() traps errors asynchronously. + */ + if (toplevel && private->accept_focus) + _gdk_macosx_set_input_focus_safe (display, toplevel->focus_window, + RevertToParent, + xevent->xclient.data.l[1]); + + return GDK_FILTER_REMOVE; + } + else if (atom == gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_PING") && + !_gdk_macosx_display_is_root_window (display, + xevent->xclient.window)) + { + XEvent xev = *xevent; + + xev.xclient.window = GDK_WINDOW_XROOTWIN (win); + XSendEvent (GDK_WINDOW_XDISPLAY (win), + xev.xclient.window, + False, + SubstructureRedirectMask | SubstructureNotifyMask, &xev); + + return GDK_FILTER_REMOVE; + } + else if (atom == gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST") && + GDK_DISPLAY_MacOSX (display)->use_sync) + { + GdkToplevelMacOSX *toplevel = _gdk_macosx_window_get_toplevel (event->any.window); + if (toplevel) + { +#ifdef HAVE_XSYNC + XSyncIntsToValue (&toplevel->pending_counter_value, + xevent->xclient.data.l[2], + xevent->xclient.data.l[3]); +#endif + } + return GDK_FILTER_REMOVE; + } + + return GDK_FILTER_CONTINUE; +} +#endif + +void +_gdk_events_queue (GdkDisplay *display) +{ + while (!_gdk_event_queue_find_first(display)) + { + /* FIXME */ + } +} + + +#if 0 +static gboolean +gdk_event_prepare (GSource *source, + gint *timeout) +{ + GdkDisplay *display = ((GdkDisplaySource*)source)->display; + gboolean retval; + + GDK_THREADS_ENTER (); + + *timeout = -1; + retval = (_gdk_event_queue_find_first (display) != NULL || + gdk_check_xpending (display)); + + GDK_THREADS_LEAVE (); + + return retval; +} + +static gboolean +gdk_event_check (GSource *source) +{ + GdkDisplaySource *display_source = (GdkDisplaySource*)source; + gboolean retval; + + GDK_THREADS_ENTER (); + + if (display_source->event_poll_fd.revents & G_IO_IN) + retval = (_gdk_event_queue_find_first (display_source->display) != NULL || + gdk_check_xpending (display_source->display)); + else + retval = FALSE; + + GDK_THREADS_LEAVE (); + + return retval; +} + +static gboolean +gdk_event_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + GdkDisplay *display = ((GdkDisplaySource*)source)->display; + GdkEvent *event; + + GDK_THREADS_ENTER (); + + _gdk_events_queue (display); + event = _gdk_event_unqueue (display); + + if (event) + { + if (_gdk_event_func) + (*_gdk_event_func) (event, _gdk_event_data); + + gdk_event_free (event); + } + + GDK_THREADS_LEAVE (); + + return TRUE; +} +#endif + +/** + * gdk_event_send_client_message_for_display: + * @display: the #GdkDisplay for the window where the message is to be sent. + * @event: the #GdkEvent to send, which should be a #GdkEventClient. + * @winid: the window to send the client message to. + * + * On X11, sends an X ClientMessage event to a given window. On + * Windows, sends a message registered with the name + * GDK_WIN32_CLIENT_MESSAGE. + * + * This could be used for communicating between different + * applications, though the amount of data is limited to 20 bytes on + * X11, and to just four bytes on Windows. + * + * Returns: non-zero on success. + * + * Since: 2.2 + */ +gboolean +gdk_event_send_client_message_for_display (GdkDisplay *display, + GdkEvent *event, + GdkNativeWindow winid) +{ + NSEvent *sev; + + g_return_if_fail (event != NULL); + + sev = [NSEvent otherEventWithType:NSApplicationDefined + location:NSMakePoint(0,0) + modifierFlags:0 + timestamp:0 + windowNumber:[(NSWindow*)winid windowNumber] + context:nil + subtype:GDK_NS_CLIENT_MESSAGE + data1:event->client.data.l[0] + data2:event->client.data.l[1]]; + + + [(NSWindow*)winid sendEvent:sev]; + + return TRUE; +} + + +#if 0 +/* Sends a ClientMessage to all toplevel client windows */ +static gboolean +gdk_event_send_client_message_to_all_recurse (GdkDisplay *display, + XEvent *xev, + guint32 xid, + guint level) +{ + Atom type = None; + int format; + unsigned long nitems, after; + unsigned char *data; + Window *ret_children, ret_root, ret_parent; + unsigned int ret_nchildren; + gboolean send = FALSE; + gboolean found = FALSE; + gboolean result = FALSE; + int i; + + gdk_error_trap_push (); + + if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid, + gdk_macosx_get_xatom_by_name_for_display (display, "WM_STATE"), + 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &data) != Success) + goto out; + + if (type) + { + send = TRUE; + XFree (data); + } + else + { + /* OK, we're all set, now let's find some windows to send this to */ + if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xid, + &ret_root, &ret_parent, + &ret_children, &ret_nchildren)) + goto out; + + for(i = 0; i < ret_nchildren; i++) + if (gdk_event_send_client_message_to_all_recurse (display, xev, ret_children[i], level + 1)) + found = TRUE; + + XFree (ret_children); + } + + if (send || (!found && (level == 1))) + { + xev->xclient.window = xid; + _gdk_send_xevent (display, xid, False, NoEventMask, xev); + } + + result = send || found; + + out: + gdk_error_trap_pop (); + + return result; +} +#endif + +/** + * gdk_screen_broadcast_client_message: + * @screen: the #GdkScreen where the event will be broadcasted. + * @event: the #GdkEvent. + * + * On MacOSX, sends an X ClientMessage event to all toplevel windows on + * @screen. + * + * Toplevel windows are determined by checking for the WM_STATE property, + * as described in the Inter-Client Communication Conventions Manual (ICCCM). + * If no windows are found with the WM_STATE property set, the message is + * sent to all children of the root window. + * + * On Windows, broadcasts a message registered with the name + * GDK_WIN32_CLIENT_MESSAGE to all top-level windows. The amount of + * data is limited to one long, i.e. four bytes. + * + * Since: 2.2 + */ + +void +gdk_screen_broadcast_client_message (GdkScreen *screen, + GdkEvent *event) +{ + NSEvent *sev; + GdkWindow *root_window; + + g_return_if_fail (event != NULL); + + root_window = gdk_screen_get_root_window (screen); + + sev = [NSEvent otherEventWithType:NSApplicationDefined + location:NSMakePoint(0,0) + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:GDK_NS_CLIENT_MESSAGE + data1:event->client.data.l[0] + data2:event->client.data.l[1]]; + + + // FIXME + +// gdk_event_send_client_message_to_all_recurse (gdk_screen_get_display (screen), +// &sev, +// GDK_WINDOW_XID (root_window), +// 0); +} + +/* + *-------------------------------------------------------------- + * gdk_flush + * + * Flushes the Xlib output buffer and then waits + * until all requests have been received and processed + * by the X server. The only real use for this function + * is in dealing with XShm. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_flush (void) +{ + /* do nothing on MacOS X */ +} + + + +#if 0 +static Bool +timestamp_predicate (Display *display, + XEvent *xevent, + XPointer arg) +{ + Window xwindow = GPOINTER_TO_UINT (arg); + GdkDisplay *gdk_display = gdk_macosx_lookup_xdisplay (display); + + if (xevent->type == PropertyNotify && + xevent->xproperty.window == xwindow && + xevent->xproperty.atom == gdk_macosx_get_xatom_by_name_for_display (gdk_display, + "GDK_TIMESTAMP_PROP")) + return True; + + return False; +} + +/** + * gdk_macosx_get_server_time: + * @window: a #GdkWindow, used for communication with the server. + * The window must have GDK_PROPERTY_CHANGE_MASK in its + * events mask or a hang will result. + * + * Routine to get the current X server time stamp. + * + * Return value: the time stamp. + **/ +guint32 +gdk_macosx_get_server_time (GdkWindow *window) +{ + Display *xdisplay; + Window xwindow; + guchar c = 'a'; + XEvent xevent; + Atom timestamp_prop_atom; + + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0); + + xdisplay = GDK_WINDOW_XDISPLAY (window); + xwindow = GDK_WINDOW_XWINDOW (window); + timestamp_prop_atom = + gdk_macosx_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), + "GDK_TIMESTAMP_PROP"); + + XChangeProperty (xdisplay, xwindow, timestamp_prop_atom, + timestamp_prop_atom, + 8, PropModeReplace, &c, 1); + + XIfEvent (xdisplay, &xevent, + timestamp_predicate, GUINT_TO_POINTER(xwindow)); + + return xevent.xproperty.time; +} + +static void +fetch_net_wm_check_window (GdkScreen *screen) +{ + GdkScreenMacOSX *screen_macosx; + GdkDisplay *display; + Atom type; + gint format; + gulong n_items; + gulong bytes_after; + guchar *data; + Window *xwindow; + + /* This function is very slow on every call if you are not running a + * spec-supporting WM. For now not optimized, because it isn't in + * any critical code paths, but if you used it somewhere that had to + * be fast you want to avoid "GTK is slow with old WMs" complaints. + * Probably at that point the function should be changed to query + * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something. + */ + + screen_macosx = GDK_SCREEN_MacOSX (screen); + display = screen_macosx->display; + + if (screen_macosx->wmspec_check_window != None) + return; /* already have it */ + + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_macosx->xroot_window, + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"), + 0, G_MAXLONG, False, XA_WINDOW, &type, &format, + &n_items, &bytes_after, &data); + + if (type != XA_WINDOW) + return; + + xwindow = (Window *)data; + + gdk_error_trap_push (); + + /* Find out if this WM goes away, so we can reset everything. */ + XSelectInput (screen_macosx->xdisplay, *xwindow, StructureNotifyMask); + gdk_display_sync (display); + + if (gdk_error_trap_pop () == Success) + { + screen_macosx->wmspec_check_window = *xwindow; + XFree (xwindow); + + screen_macosx->need_refetch_net_supported = TRUE; + screen_macosx->need_refetch_wm_name = TRUE; + + /* Careful, reentrancy */ + _gdk_macosx_screen_window_manager_changed (GDK_SCREEN (screen_macosx)); + } +} + +/** + * gdk_macosx_screen_get_window_manager_name: + * @screen: a #GdkScreen + * + * Returns the name of the window manager for @screen. + * + * Return value: the name of the window manager screen @screen, or + * "unknown" if the window manager is unknown. The string is owned by GDK + * and should not be freed. + * + * Since: 2.2 + **/ +const char* +gdk_macosx_screen_get_window_manager_name (GdkScreen *screen) +{ + GdkScreenMacOSX *screen_macosx; + + screen_macosx = GDK_SCREEN_MacOSX (screen); + + fetch_net_wm_check_window (screen); + + if (screen_macosx->need_refetch_wm_name) + { + /* Get the name of the window manager */ + screen_macosx->need_refetch_wm_name = FALSE; + + g_free (screen_macosx->window_manager_name); + screen_macosx->window_manager_name = g_strdup ("unknown"); + + if (screen_macosx->wmspec_check_window != None) + { + Atom type; + gint format; + gulong n_items; + gulong bytes_after; + guchar *name; + + name = NULL; + + gdk_error_trap_push (); + + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (screen_macosx->display), + screen_macosx->wmspec_check_window, + gdk_macosx_get_xatom_by_name_for_display (screen_macosx->display, + "_NET_WM_NAME"), + 0, G_MAXLONG, False, + gdk_macosx_get_xatom_by_name_for_display (screen_macosx->display, + "UTF8_STRING"), + &type, &format, + &n_items, &bytes_after, + (guchar **)&name); + + gdk_display_sync (screen_macosx->display); + + gdk_error_trap_pop (); + + if (name != NULL) + { + g_free (screen_macosx->window_manager_name); + screen_macosx->window_manager_name = g_strdup (name); + XFree (name); + } + } + } + + return GDK_SCREEN_MacOSX (screen)->window_manager_name; +} +#endif + +/** + * gdk_screen_get_setting: + * @screen: the #GdkScreen where the setting is located + * @name: the name of the setting + * @value: location to store the value of the setting + * + * Retrieves a desktop-wide setting such as double-click time + * for the #GdkScreen @screen. + * + * FIXME needs a list of valid settings here, or a link to + * more information. + * + * Returns: %TRUE if the setting existed and a value was stored + * in @value, %FALSE otherwise. + * + * Since: 2.2 + **/ +gboolean +gdk_screen_get_setting (GdkScreen *screen, + const gchar *name, + GValue *value) +{ + + if (strcmp ("gtk-theme-name", name) == 0) + { + g_value_set_string (value, "aqua"); + return TRUE; + } +#if 0 + /*stolen from Win32*/ + else if (strcmp ("gtk-double-click-time", name) == 0) + { + gint i = GetDoubleClickTime (); + GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i)); + g_value_set_int (value, i); + return TRUE; + } + else if (strcmp ("gtk-double-click-distance", name) == 0) + { + gint i = MAX(GetSystemMetrics (SM_CXDOUBLECLK), GetSystemMetrics (SM_CYDOUBLECLK)); + GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i)); + g_value_set_int (value, i); + return TRUE; + } + else if (strcmp ("gtk-dnd-drag-threshold", name) == 0) + { + gint i = MAX(GetSystemMetrics (SM_CXDRAG), GetSystemMetrics (SM_CYDRAG)); + GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i)); + g_value_set_int (value, i); + return TRUE; + } + else if (strcmp ("gtk-split-cursor", name) == 0) + { + GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : FALSE\n", name)); + g_value_set_boolean (value, FALSE); + return TRUE; + } +#endif + else { + GDK_NOTE(MSIC, g_print("Requested setting %s that is unknown\n", name)); + } + return FALSE; +} + +#if 0 +static GdkFilterReturn +gdk_xsettings_client_event_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + GdkScreenMacOSX *screen = data; + + if (xsettings_client_process_event (screen->xsettings_client, (XEvent *)xevent)) + return GDK_FILTER_REMOVE; + else + return GDK_FILTER_CONTINUE; +} + +static void +gdk_xsettings_watch_cb (Window window, + Bool is_start, + long mask, + void *cb_data) +{ + GdkWindow *gdkwin; + GdkScreen *screen = cb_data; + + gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window); + + if (is_start) + { + if (!gdkwin) + gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window); + else + g_object_ref (gdkwin); + + gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen); + } + else + { + g_assert (gdkwin); + gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen); + g_object_unref (gdkwin); + } +} + + +#endif diff --git a/gdk/macosx/gdkgc-macosx.m b/gdk/macosx/gdkgc-macosx.m new file mode 100644 index 0000000000..f7744893e4 --- /dev/null +++ b/gdk/macosx/gdkgc-macosx.m @@ -0,0 +1,1306 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include <config.h> + +#include "gdkalias.h" +#include "gdkgc.h" +#include "gdkprivate-macosx.h"*/ +#include "gdkregion-generic.h" + +#include <string.h> + +typedef enum { + GDK_GC_DIRTY_CLIP = 1 << 0, + GDK_GC_DIRTY_TS = 1 << 1 +} GdkGCDirtyValues; + +#if 0 + +static void gdk_macosx_gc_values_to_xvalues (GdkGCValues *values, + GdkGCValuesMask mask, + XGCValues *xvalues, + unsigned long *xvalues_mask); +#endif + +static void gdk_macosx_gc_get_values (GdkGC *gc, + GdkGCValues *values); +static void gdk_macosx_gc_set_values (GdkGC *gc, + GdkGCValues *values, + GdkGCValuesMask values_mask); +static void gdk_macosx_gc_set_dashes (GdkGC *gc, + gint dash_offset, + gint8 dash_list[], + gint n); + +static void gdk_gc_macosx_class_init (GdkGCMacOSXClass *klass); +static void gdk_gc_macosx_finalize (GObject *object); + +static gpointer parent_class = NULL; + + +GType +_gdk_gc_macosx_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (GdkGCMacOSXClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gdk_gc_macosx_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GdkGCMacOSX), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + }; + + object_type = g_type_register_static (GDK_TYPE_GC, + "GdkGCMacOSX", + &object_info, 0); + } + + return object_type; +} + +static void +gdk_gc_macosx_class_init (GdkGCMacOSXClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkGCClass *gc_class = GDK_GC_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = gdk_gc_macosx_finalize; + + gc_class->get_values = gdk_macosx_gc_get_values; + gc_class->set_values = gdk_macosx_gc_set_values; + gc_class->set_dashes = gdk_macosx_gc_set_dashes; +} + +#if 0 +static void +gdk_gc_macosx_finalize (GObject *object) +{ + GdkGCMacOSX *macosx_gc = GDK_GC_MacOSX (object); + + if (macosx_gc->clip_region) + gdk_region_destroy (macosx_gc->clip_region); + + if (macosx_gc->fg_picture != None) + XRenderFreePicture (GDK_GC_XDISPLAY (macosx_gc), macosx_gc->fg_picture); + + if (macosx_gc->stipple) + g_object_unref (macosx_gc->stipple); + if (macosx_gc->tile) + g_object_unref (macosx_gc->tile); + +// XFreeGC (GDK_GC_XDISPLAY (macosx_gc), GDK_GC_XGC (macosx_gc)); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} +#endif + +#if 0 +GdkGC * +_gdk_macosx_gc_new (GdkDrawable *drawable, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GdkGC *gc; + GdkGCMacOSX *private; + + XGCValues xvalues; + unsigned long xvalues_mask; + + /* NOTICE that the drawable here has to be the impl drawable, + * not the publically-visible drawables. + */ + g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_MACOSX (drawable), NULL); + + gc = g_object_new (_gdk_gc_macosx_get_type (), NULL); + private = GDK_GC_MacOSX (gc); + + private->dirty_mask = 0; + private->have_clip_mask = FALSE; + private->clip_region = NULL; + + private->screen = GDK_DRAWABLE_IMPL_MacOSX (drawable)->screen; + + private->depth = gdk_drawable_get_depth (drawable); + + if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN)) + { + values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN); + private->dirty_mask |= GDK_GC_DIRTY_CLIP; + } + + if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN)) + { + values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN); + private->dirty_mask |= GDK_GC_DIRTY_TS; + } + + if (values_mask & GDK_GC_FOREGROUND) + private->fg_pixel = values->foreground.pixel; + + if (values_mask & GDK_GC_BACKGROUND) + private->bg_pixel = values->background.pixel; + + if (values_mask & GDK_GC_FILL) + private->fill = values->fill; + + if (values_mask & GDK_GC_STIPPLE) + { + private->stipple = values->stipple; + if (private->stipple) + g_object_ref (private->stipple); + } + + if (values_mask & GDK_GC_TILE) + { + private->tile = values->tile; + if (private->tile) + g_object_ref (private->tile); + } + + if ((values_mask & GDK_GC_CLIP_MASK) && values->clip_mask) + private->have_clip_mask = TRUE; + + xvalues.function = GXcopy; + xvalues.fill_style = FillSolid; + xvalues.arc_mode = ArcPieSlice; + xvalues.subwindow_mode = ClipByChildren; + xvalues.graphics_exposures = False; + xvalues_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures; + + gdk_macosx_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask); + + private->xgc = XCreateGC (GDK_GC_XDISPLAY (gc), + GDK_DRAWABLE_IMPL_MacOSX (drawable)->xid, + xvalues_mask, &xvalues); + + return gc; +} + +GC +_gdk_macosx_gc_flush (GdkGC *gc) +{ + Display *xdisplay = GDK_GC_XDISPLAY (gc); + GdkGCMacOSX *private = GDK_GC_MacOSX (gc); + GC xgc = private->xgc; + + if (private->dirty_mask & GDK_GC_DIRTY_CLIP) + { + if (!private->clip_region) + XSetClipOrigin (xdisplay, xgc, + gc->clip_x_origin, gc->clip_y_origin); + else + { + XRectangle *rectangles; + gint n_rects; + + _gdk_region_get_xrectangles (private->clip_region, + gc->clip_x_origin, + gc->clip_y_origin, + &rectangles, + &n_rects); + + XSetClipRectangles (xdisplay, xgc, 0, 0, + rectangles, + n_rects, YXBanded); + + g_free (rectangles); + } + } + + if (private->dirty_mask & GDK_GC_DIRTY_TS) + { + XSetTSOrigin (xdisplay, xgc, + gc->ts_x_origin, gc->ts_y_origin); + } + + private->dirty_mask = 0; + return xgc; +} + +static void +gdk_macosx_gc_get_values (GdkGC *gc, + GdkGCValues *values) +{ + XGCValues xvalues; + + if (XGetGCValues (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), + GCForeground | GCBackground | GCFont | + GCFunction | GCTile | GCStipple | /* GCClipMask | */ + GCSubwindowMode | GCGraphicsExposures | + GCTileStipXOrigin | GCTileStipYOrigin | + GCClipXOrigin | GCClipYOrigin | + GCLineWidth | GCLineStyle | GCCapStyle | + GCFillStyle | GCJoinStyle, &xvalues)) + { + values->foreground.pixel = xvalues.foreground; + values->background.pixel = xvalues.background; + values->font = gdk_font_lookup_for_display (GDK_GC_DISPLAY (gc), + xvalues.font); + + switch (xvalues.function) + { + case GXcopy: + values->function = GDK_COPY; + break; + case GXinvert: + values->function = GDK_INVERT; + break; + case GXxor: + values->function = GDK_XOR; + break; + case GXclear: + values->function = GDK_CLEAR; + break; + case GXand: + values->function = GDK_AND; + break; + case GXandReverse: + values->function = GDK_AND_REVERSE; + break; + case GXandInverted: + values->function = GDK_AND_INVERT; + break; + case GXnoop: + values->function = GDK_NOOP; + break; + case GXor: + values->function = GDK_OR; + break; + case GXequiv: + values->function = GDK_EQUIV; + break; + case GXorReverse: + values->function = GDK_OR_REVERSE; + break; + case GXcopyInverted: + values->function =GDK_COPY_INVERT; + break; + case GXorInverted: + values->function = GDK_OR_INVERT; + break; + case GXnand: + values->function = GDK_NAND; + break; + case GXset: + values->function = GDK_SET; + break; + case GXnor: + values->function = GDK_NOR; + break; + } + + switch (xvalues.fill_style) + { + case FillSolid: + values->fill = GDK_SOLID; + break; + case FillTiled: + values->fill = GDK_TILED; + break; + case FillStippled: + values->fill = GDK_STIPPLED; + break; + case FillOpaqueStippled: + values->fill = GDK_OPAQUE_STIPPLED; + break; + } + + values->tile = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc), + xvalues.tile); + values->stipple = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc), + xvalues.stipple); + values->clip_mask = NULL; + values->subwindow_mode = xvalues.subwindow_mode; + values->ts_x_origin = xvalues.ts_x_origin; + values->ts_y_origin = xvalues.ts_y_origin; + values->clip_x_origin = xvalues.clip_x_origin; + values->clip_y_origin = xvalues.clip_y_origin; + values->graphics_exposures = xvalues.graphics_exposures; + values->line_width = xvalues.line_width; + + switch (xvalues.line_style) + { + case LineSolid: + values->line_style = GDK_LINE_SOLID; + break; + case LineOnOffDash: + values->line_style = GDK_LINE_ON_OFF_DASH; + break; + case LineDoubleDash: + values->line_style = GDK_LINE_DOUBLE_DASH; + break; + } + + switch (xvalues.cap_style) + { + case CapNotLast: + values->cap_style = GDK_CAP_NOT_LAST; + break; + case CapButt: + values->cap_style = GDK_CAP_BUTT; + break; + case CapRound: + values->cap_style = GDK_CAP_ROUND; + break; + case CapProjecting: + values->cap_style = GDK_CAP_PROJECTING; + break; + } + + switch (xvalues.join_style) + { + case JoinMiter: + values->join_style = GDK_JOIN_MITER; + break; + case JoinRound: + values->join_style = GDK_JOIN_ROUND; + break; + case JoinBevel: + values->join_style = GDK_JOIN_BEVEL; + break; + } + } + else + { + memset (values, 0, sizeof (GdkGCValues)); + } +} + +static void +clear_fg_picture (GdkGC *gc) +{ + GdkGCMacOSX *macosx_gc = GDK_GC_MacOSX (gc); + + if (macosx_gc->fg_picture != None) + { + XRenderFreePicture (GDK_GC_XDISPLAY (macosx_gc), macosx_gc->fg_picture); + macosx_gc->fg_picture = None; + } +} + +static void +gdk_macosx_gc_set_values (GdkGC *gc, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GdkGCMacOSX *macosx_gc; + XGCValues xvalues; + unsigned long xvalues_mask = 0; + + macosx_gc = GDK_GC_MacOSX (gc); + + if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN)) + { + values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN); + macosx_gc->dirty_mask |= GDK_GC_DIRTY_CLIP; + } + + if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN)) + { + values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN); + macosx_gc->dirty_mask |= GDK_GC_DIRTY_TS; + } + + if (values_mask & GDK_GC_CLIP_MASK) + { + if (macosx_gc->clip_region) + { + gdk_region_destroy (macosx_gc->clip_region); + macosx_gc->clip_region = NULL; + } + + macosx_gc->have_clip_mask = values->clip_mask != NULL; + } + + if (values_mask & GDK_GC_FOREGROUND) + macosx_gc->fg_pixel = values->foreground.pixel; + + if (values_mask & GDK_GC_BACKGROUND) + { + if (macosx_gc->bg_pixel != values->background.pixel) + { + macosx_gc->bg_pixel = values->background.pixel; + if (macosx_gc->fill == GDK_OPAQUE_STIPPLED) + clear_fg_picture (gc); + } + } + + if (values_mask & GDK_GC_FILL) + { + if (macosx_gc->fill != values->fill) + { + clear_fg_picture (gc); + macosx_gc->fill = values->fill; + } + } + + if (values_mask & GDK_GC_STIPPLE) + { + if (macosx_gc->stipple != values->stipple) + { + if (macosx_gc->fill == GDK_STIPPLED || macosx_gc->fill == GDK_OPAQUE_STIPPLED) + clear_fg_picture (gc); + if (macosx_gc->stipple) + g_object_unref (macosx_gc->stipple); + macosx_gc->stipple = values->stipple; + if (macosx_gc->stipple) + g_object_ref (macosx_gc->stipple); + } + } + + if (values_mask & GDK_GC_TILE) + { + if (macosx_gc->tile != values->tile) + { + if (macosx_gc->fill == GDK_TILED) + clear_fg_picture (gc); + if (macosx_gc->tile) + g_object_unref (macosx_gc->tile); + macosx_gc->tile = values->tile; + if (macosx_gc->tile) + g_object_ref (macosx_gc->tile); + } + } + + gdk_macosx_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask); + + XChangeGC (GDK_GC_XDISPLAY (gc), + GDK_GC_XGC (gc), + xvalues_mask, + &xvalues); +} + +static void +gdk_macosx_gc_set_dashes (GdkGC *gc, + gint dash_offset, + gint8 dash_list[], + gint n) +{ + g_return_if_fail (GDK_IS_GC (gc)); + g_return_if_fail (dash_list != NULL); + + XSetDashes (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), + dash_offset, dash_list, n); +} + +static void +gdk_macosx_gc_values_to_xvalues (GdkGCValues *values, + GdkGCValuesMask mask, + XGCValues *xvalues, + unsigned long *xvalues_mask) +{ + /* Optimization for the common case (gdk_gc_new()) */ + if (values == NULL || mask == 0) + return; + + if (mask & GDK_GC_FOREGROUND) + { + xvalues->foreground = values->foreground.pixel; + *xvalues_mask |= GCForeground; + } + if (mask & GDK_GC_BACKGROUND) + { + xvalues->background = values->background.pixel; + *xvalues_mask |= GCBackground; + } + if ((mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT)) + { + xvalues->font = ((XFontStruct *) (GDK_FONT_XFONT (values->font)))->fid; + *xvalues_mask |= GCFont; + } + if (mask & GDK_GC_FUNCTION) + { + switch (values->function) + { + case GDK_COPY: + xvalues->function = GXcopy; + break; + case GDK_INVERT: + xvalues->function = GXinvert; + break; + case GDK_XOR: + xvalues->function = GXxor; + break; + case GDK_CLEAR: + xvalues->function = GXclear; + break; + case GDK_AND: + xvalues->function = GXand; + break; + case GDK_AND_REVERSE: + xvalues->function = GXandReverse; + break; + case GDK_AND_INVERT: + xvalues->function = GXandInverted; + break; + case GDK_NOOP: + xvalues->function = GXnoop; + break; + case GDK_OR: + xvalues->function = GXor; + break; + case GDK_EQUIV: + xvalues->function = GXequiv; + break; + case GDK_OR_REVERSE: + xvalues->function = GXorReverse; + break; + case GDK_COPY_INVERT: + xvalues->function = GXcopyInverted; + break; + case GDK_OR_INVERT: + xvalues->function = GXorInverted; + break; + case GDK_NAND: + xvalues->function = GXnand; + break; + case GDK_SET: + xvalues->function = GXset; + break; + case GDK_NOR: + xvalues->function = GXnor; + break; + } + *xvalues_mask |= GCFunction; + } + if (mask & GDK_GC_FILL) + { + switch (values->fill) + { + case GDK_SOLID: + xvalues->fill_style = FillSolid; + break; + case GDK_TILED: + xvalues->fill_style = FillTiled; + break; + case GDK_STIPPLED: + xvalues->fill_style = FillStippled; + break; + case GDK_OPAQUE_STIPPLED: + xvalues->fill_style = FillOpaqueStippled; + break; + } + *xvalues_mask |= GCFillStyle; + } + if (mask & GDK_GC_TILE) + { + if (values->tile) + xvalues->tile = GDK_DRAWABLE_XID (values->tile); + else + xvalues->tile = None; + + *xvalues_mask |= GCTile; + } + if (mask & GDK_GC_STIPPLE) + { + if (values->stipple) + xvalues->stipple = GDK_DRAWABLE_XID (values->stipple); + else + xvalues->stipple = None; + + *xvalues_mask |= GCStipple; + } + if (mask & GDK_GC_CLIP_MASK) + { + if (values->clip_mask) + xvalues->clip_mask = GDK_DRAWABLE_XID (values->clip_mask); + else + xvalues->clip_mask = None; + + *xvalues_mask |= GCClipMask; + + } + if (mask & GDK_GC_SUBWINDOW) + { + xvalues->subwindow_mode = values->subwindow_mode; + *xvalues_mask |= GCSubwindowMode; + } + if (mask & GDK_GC_TS_X_ORIGIN) + { + xvalues->ts_x_origin = values->ts_x_origin; + *xvalues_mask |= GCTileStipXOrigin; + } + if (mask & GDK_GC_TS_Y_ORIGIN) + { + xvalues->ts_y_origin = values->ts_y_origin; + *xvalues_mask |= GCTileStipYOrigin; + } + if (mask & GDK_GC_CLIP_X_ORIGIN) + { + xvalues->clip_x_origin = values->clip_x_origin; + *xvalues_mask |= GCClipXOrigin; + } + if (mask & GDK_GC_CLIP_Y_ORIGIN) + { + xvalues->clip_y_origin = values->clip_y_origin; + *xvalues_mask |= GCClipYOrigin; + } + + if (mask & GDK_GC_EXPOSURES) + { + xvalues->graphics_exposures = values->graphics_exposures; + *xvalues_mask |= GCGraphicsExposures; + } + + if (mask & GDK_GC_LINE_WIDTH) + { + xvalues->line_width = values->line_width; + *xvalues_mask |= GCLineWidth; + } + if (mask & GDK_GC_LINE_STYLE) + { + switch (values->line_style) + { + case GDK_LINE_SOLID: + xvalues->line_style = LineSolid; + break; + case GDK_LINE_ON_OFF_DASH: + xvalues->line_style = LineOnOffDash; + break; + case GDK_LINE_DOUBLE_DASH: + xvalues->line_style = LineDoubleDash; + break; + } + *xvalues_mask |= GCLineStyle; + } + if (mask & GDK_GC_CAP_STYLE) + { + switch (values->cap_style) + { + case GDK_CAP_NOT_LAST: + xvalues->cap_style = CapNotLast; + break; + case GDK_CAP_BUTT: + xvalues->cap_style = CapButt; + break; + case GDK_CAP_ROUND: + xvalues->cap_style = CapRound; + break; + case GDK_CAP_PROJECTING: + xvalues->cap_style = CapProjecting; + break; + } + *xvalues_mask |= GCCapStyle; + } + if (mask & GDK_GC_JOIN_STYLE) + { + switch (values->join_style) + { + case GDK_JOIN_MITER: + xvalues->join_style = JoinMiter; + break; + case GDK_JOIN_ROUND: + xvalues->join_style = JoinRound; + break; + case GDK_JOIN_BEVEL: + xvalues->join_style = JoinBevel; + break; + } + *xvalues_mask |= GCJoinStyle; + } + +} + +/** + * gdk_gc_set_clip_rectangle: + * @gc: a #GdkGC. + * @rectangle: the rectangle to clip to. + * + * Sets the clip mask for a graphics context from a + * rectangle. The clip mask is interpreted relative to the clip + * origin. (See gdk_gc_set_clip_origin()). + **/ +void +gdk_gc_set_clip_rectangle (GdkGC *gc, + GdkRectangle *rectangle) +{ + GdkGCMacOSX *macosx_gc; + gboolean had_region = FALSE; + + g_return_if_fail (GDK_IS_GC (gc)); + + macosx_gc = GDK_GC_MacOSX (gc); + + if (macosx_gc->clip_region) + { + had_region = TRUE; + gdk_region_destroy (macosx_gc->clip_region); + } + + if (rectangle) + macosx_gc->clip_region = gdk_region_rectangle (rectangle); + else + macosx_gc->clip_region = NULL; + + /* Unset immediately, to make sure Xlib doesn't keep the + * XID of an old clip mask cached + */ + if ((had_region && !rectangle) || macosx_gc->have_clip_mask) + { + XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None); + macosx_gc->have_clip_mask = FALSE; + } + + gc->clip_x_origin = 0; + gc->clip_y_origin = 0; + + macosx_gc->dirty_mask |= GDK_GC_DIRTY_CLIP; +} +#endif + +/** + * gdk_gc_set_clip_region: + * @gc: a #GdkGC. + * @region: the #GdkRegion. + * + * Sets the clip mask for a graphics context from a region structure. + * The clip mask is interpreted relative to the clip origin. (See + * gdk_gc_set_clip_origin()). + **/ +void +gdk_gc_set_clip_region (GdkGC *gc, + GdkRegion *region) +{ + GdkGCMacOSX *macosx_gc; + gboolean had_region = FALSE; + + g_return_if_fail (GDK_IS_GC (gc)); + + macosx_gc = GDK_GC_MACOSX (gc); + + if (macosx_gc->clip_region) + { + had_region = TRUE; + gdk_region_destroy (macosx_gc->clip_region); + } + + if (region) + macosx_gc->clip_region = gdk_region_copy (region); + else + macosx_gc->clip_region = NULL; + + if ((had_region && !region) || macosx_gc->have_clip_mask) + { + // FIXME + CGContextRestoreGState(macosx_gc->cggc); + CGContextSaveGState(macosx_gc->cggc); + //CGContextClip(macosx_gc->gccg); +// XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None); + macosx_gc->have_clip_mask = FALSE; + } + + gc->clip_x_origin = 0; + gc->clip_y_origin = 0; + + macosx_gc->dirty_mask |= GDK_GC_DIRTY_CLIP; +} + +#if 0 + +/** + * gdk_gc_copy: + * @dst_gc: the destination graphics context. + * @src_gc: the source graphics context. + * + * Copy the set of values from one graphics context + * onto another graphics context. + **/ +void +gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc) +{ + GdkGCMacOSX *macosx_src_gc; + GdkGCMacOSX *macosx_dst_gc; + + g_return_if_fail (GDK_IS_GC_MacOSX (dst_gc)); + g_return_if_fail (GDK_IS_GC_MacOSX (src_gc)); + + macosx_dst_gc = GDK_GC_MacOSX (dst_gc); + macosx_src_gc = GDK_GC_MacOSX (src_gc); + + XCopyGC (GDK_GC_XDISPLAY (src_gc), GDK_GC_XGC (src_gc), ~((~1) << GCLastBit), + GDK_GC_XGC (dst_gc)); + + dst_gc->clip_x_origin = src_gc->clip_x_origin; + dst_gc->clip_y_origin = src_gc->clip_y_origin; + dst_gc->ts_x_origin = src_gc->ts_x_origin; + dst_gc->ts_y_origin = src_gc->ts_y_origin; + + if (src_gc->colormap) + g_object_ref (src_gc->colormap); + + if (dst_gc->colormap) + g_object_unref (dst_gc->colormap); + + dst_gc->colormap = src_gc->colormap; + + if (macosx_dst_gc->clip_region) + gdk_region_destroy (macosx_dst_gc->clip_region); + + if (macosx_src_gc->clip_region) + macosx_dst_gc->clip_region = gdk_region_copy (macosx_src_gc->clip_region); + else + macosx_dst_gc->clip_region = NULL; + + macosx_dst_gc->dirty_mask = macosx_src_gc->dirty_mask; + macosx_dst_gc->fg_pixel = macosx_src_gc->fg_pixel; + macosx_dst_gc->fill = macosx_src_gc->fill; + + if (macosx_dst_gc->stipple) + g_object_unref (macosx_dst_gc->stipple); + macosx_dst_gc->stipple = macosx_src_gc->stipple; + if (macosx_dst_gc->stipple) + g_object_ref (macosx_dst_gc->stipple); + + if (macosx_dst_gc->tile) + g_object_unref (macosx_dst_gc->tile); + macosx_dst_gc->tile = macosx_src_gc->tile; + if (macosx_dst_gc->tile) + g_object_ref (macosx_dst_gc->tile); + + clear_fg_picture (dst_gc); +} + +/** + * gdk_gc_get_screen: + * @gc: a #GdkGC. + * + * Gets the #GdkScreen for which @gc was created + * + * Returns: the #GdkScreen for @gc. + * + * Since: 2.2 + */ +GdkScreen * +gdk_gc_get_screen (GdkGC *gc) +{ + g_return_val_if_fail (GDK_IS_GC_MacOSX (gc), NULL); + + return GDK_GC_MacOSX (gc)->screen; +} + +/** + * gdk_macosx_gc_get_xdisplay: + * @gc: a #GdkGC. + * + * Returns the display of a #GdkGC. + * + * Return value: an Xlib <type>Display*</type>. + **/ +Display * +gdk_macosx_gc_get_xdisplay (GdkGC *gc) +{ + g_return_val_if_fail (GDK_IS_GC_MacOSX (gc), NULL); + + return GDK_SCREEN_XDISPLAY (gdk_gc_get_screen (gc)); +} + +/** + * gdk_macosx_gc_get_xgc: + * @gc: a #GdkGC. + * + * Returns the X GC of a #GdkGC. + * + * Return value: an Xlib <type>GC</type>. + **/ +GC +gdk_macosx_gc_get_xgc (GdkGC *gc) +{ + GdkGCMacOSX *gc_macosx; + + g_return_val_if_fail (GDK_IS_GC_MacOSX (gc), NULL); + + gc_macosx = GDK_GC_MacOSX (gc); + + if (gc_macosx->dirty_mask) + _gdk_macosx_gc_flush (gc); + + return gc_macosx->xgc; +} + +/* Various bits of the below are roughly cribbed from XFree86 + * lib/Xft/xftdraw.c, Copyright 2000, Keith Packard + */ + +static XRenderPictFormat * +foreground_format (GdkGC *gc) +{ + XRenderPictFormat pf; + + pf.type = PictTypeDirect; + pf.depth = 32; + pf.direct.redMask = 0xff; + pf.direct.greenMask = 0xff; + pf.direct.blueMask = 0xff; + pf.direct.alphaMask = 0xff; + + return XRenderFindFormat (GDK_GC_XDISPLAY (gc), + (PictFormatType | + PictFormatDepth | + PictFormatRedMask | + PictFormatGreenMask | + PictFormatBlueMask | + PictFormatAlphaMask), + &pf, + 0); +} + +static Picture +make_fg_tile_picture (GdkGC *gc) +{ + GdkGCMacOSX *macosx_gc = GDK_GC_MacOSX (gc); + GdkVisual *visual = gdk_drawable_get_visual (macosx_gc->tile); + XRenderPictFormat *format = NULL; + + if (visual) + { + format = XRenderFindVisualFormat (GDK_GC_XDISPLAY (gc), + GDK_VISUAL_XVISUAL (visual)); + } + else if (macosx_gc->depth == 1) + { + format = XRenderFindStandardFormat (GDK_GC_XDISPLAY (gc), + PictStandardA1); + } + + if (format) + { + XRenderPictureAttributes pa; + pa.repeat = True; + + return XRenderCreatePicture (GDK_GC_XDISPLAY (gc), + GDK_PIXMAP_XID (macosx_gc->tile), + format, + CPRepeat, &pa); + } + + return None; +} + +static Picture +make_stipple_picture (GdkGC *gc) +{ + GdkGCMacOSX *macosx_gc = GDK_GC_MacOSX (gc); + XRenderPictFormat *format = NULL; + XRenderPictureAttributes pa; + + format = XRenderFindStandardFormat (GDK_GC_XDISPLAY (gc), + PictStandardA1); + + pa.repeat = True; + return XRenderCreatePicture (GDK_GC_XDISPLAY (gc), + GDK_PIXMAP_XID (macosx_gc->stipple), + format, + CPRepeat, &pa); +} + +static Picture +make_color_picture (GdkGC *gc, + XRenderColor *color) +{ + GdkGCMacOSX *macosx_gc = GDK_GC_MacOSX (gc); + XRenderPictureAttributes pa; + XRenderPictFormat *pix_format = foreground_format (gc); + Pixmap pix; + Picture picture; + + if (!pix_format) + return None; + + pix = XCreatePixmap (GDK_GC_XDISPLAY (gc), + GDK_SCREEN_XROOTWIN (macosx_gc->screen), + 1, 1, pix_format->depth); + pa.repeat = True; + picture = XRenderCreatePicture (GDK_GC_XDISPLAY (gc), + pix, + pix_format, + CPRepeat, &pa); + XFreePixmap (GDK_GC_XDISPLAY (gc), pix); + + XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc, + picture, color, + 0, 0, 1, 1); + + return picture; +} + +static void +get_bg_color (GdkGC *gc, + XRenderColor *render_color) +{ + GdkGCMacOSX *macosx_gc = GDK_GC_MacOSX (gc); + GdkColormap *cmap; + + cmap = gdk_gc_get_colormap (gc); + + if (cmap) + { + GdkColor color; + + gdk_colormap_query_color (cmap, macosx_gc->bg_pixel, &color); + + render_color->alpha = 0xffff; + render_color->red = color.red; + render_color->green = color.green; + render_color->blue = color.blue; + } + else /* Not worth warning, just use black */ + { + render_color->alpha = 0xffff; + render_color->red = 0; + render_color->green = 0; + render_color->blue = 0; + } +} + +/** + * _gdk_macosx_gc_get_fg_picture: + * @gc: a #GdkGC + * + * Gets a Xrender Picture object suitable for being the source + * drawable for drawing with the foreground the graphics context. + * + * Return value: a Picture, owned by the GC; this cannot be + * used over subsequent modification of the GC. + **/ +Picture +_gdk_macosx_gc_get_fg_picture (GdkGC *gc) +{ + GdkGCMacOSX *macosx_gc; + gboolean new = FALSE; + XftColor xftcolor; + GdkFill fill; + int width, height; + + g_return_val_if_fail (GDK_IS_GC_MacOSX (gc), None); + + if (!_gdk_macosx_have_render (GDK_GC_DISPLAY (gc))) + return None; + + macosx_gc = GDK_GC_MacOSX (gc); + + fill = GDK_SOLID; + width = 1; + height = 1; + + switch (macosx_gc->fill) + { + case GDK_SOLID: + break; + case GDK_TILED: + if (macosx_gc->tile) + { + if (!macosx_gc->fg_picture) + macosx_gc->fg_picture = make_fg_tile_picture (gc); + + if (macosx_gc->fg_picture != None) + return macosx_gc->fg_picture; + } + break; + case GDK_STIPPLED: + case GDK_OPAQUE_STIPPLED: + if (macosx_gc->stipple) + { + gdk_drawable_get_size (macosx_gc->stipple, &width, &height); + fill = macosx_gc->fill; + } + break; + } + + if (macosx_gc->fg_picture == None) + { + XRenderPictureAttributes pa; + XRenderPictFormat *pix_format = foreground_format (gc); + Pixmap pix; + + if (!pix_format) + return None; + + pix = XCreatePixmap (GDK_GC_XDISPLAY (gc), + GDK_SCREEN_XROOTWIN (macosx_gc->screen), + width, height, pix_format->depth); + pa.repeat = True; + macosx_gc->fg_picture = XRenderCreatePicture (GDK_GC_XDISPLAY (gc), + pix, + pix_format, + CPRepeat, &pa); + XFreePixmap (GDK_GC_XDISPLAY (gc), pix); + + new = TRUE; + } + + _gdk_gc_macosx_get_fg_xft_color (gc, &xftcolor); + + if (macosx_gc->fg_picture_color.alpha != 0xffff || + macosx_gc->fg_picture_color.red != xftcolor.color.red || + macosx_gc->fg_picture_color.green != xftcolor.color.green || + macosx_gc->fg_picture_color.blue != xftcolor.color.blue) + { + macosx_gc->fg_picture_color.alpha = 0xffff; + macosx_gc->fg_picture_color.red = xftcolor.color.red; + macosx_gc->fg_picture_color.green = xftcolor.color.green; + macosx_gc->fg_picture_color.blue = xftcolor.color.blue; + + new = TRUE; + } + + switch (fill) + { + case GDK_SOLID: + XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc, + macosx_gc->fg_picture, &macosx_gc->fg_picture_color, + 0, 0, width, height); + break; + case GDK_STIPPLED: + { + Picture stipple_picture = make_stipple_picture (gc); + + XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc, + macosx_gc->fg_picture, &macosx_gc->fg_picture_color, + 0, 0, width, height); + XRenderComposite (GDK_GC_XDISPLAY (gc), + PictOpInReverse, + stipple_picture, None, macosx_gc->fg_picture, + 0, 0, 0, 0, 0, 0, width, height); + + XRenderFreePicture (GDK_GC_XDISPLAY (macosx_gc), stipple_picture); + } + break; + case GDK_OPAQUE_STIPPLED: + { + XRenderColor bg_color; + + Picture stipple_picture = make_stipple_picture (gc); + Picture fg_picture = make_color_picture (gc, &macosx_gc->fg_picture_color); + + get_bg_color (gc, &bg_color); + + XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc, + macosx_gc->fg_picture, &bg_color, + 0, 0, width, height); + XRenderComposite (GDK_GC_XDISPLAY (gc), + PictOpOver, + fg_picture, stipple_picture, macosx_gc->fg_picture, + 0, 0, 0, 0, 0, 0, width, height); + + XRenderFreePicture (GDK_GC_XDISPLAY (macosx_gc), stipple_picture); + XRenderFreePicture (GDK_GC_XDISPLAY (macosx_gc), fg_picture); + } + break; + case GDK_TILED: + g_assert_not_reached (); /* handled above */ + break; + } + + return macosx_gc->fg_picture; +} + +/** + * _gdk_gc_macosx_get_fg_xft_color: + * @gc: a #GdkGC + * @xftcolor: location to store the color + * + * Gets the foreground color of the GC as a XftColor. + **/ +void +_gdk_gc_macosx_get_fg_xft_color (GdkGC *gc, + XftColor *xftcolor) +{ + GdkGCMacOSX *macosx_gc; + GdkColormap *cmap; + GdkColor color; + + g_return_if_fail (GDK_IS_GC_MacOSX (gc)); + + macosx_gc = GDK_GC_MacOSX (gc); + + cmap = gdk_gc_get_colormap (gc); + + xftcolor->pixel = macosx_gc->fg_pixel; + + if (cmap) + { + gdk_colormap_query_color (cmap, xftcolor->pixel, &color); + xftcolor->color.alpha = 0xffff; + xftcolor->color.red = color.red; + xftcolor->color.green = color.green; + xftcolor->color.blue = color.blue; + } + else if (macosx_gc->depth == 1) + { + /* Drawing with Xft on a bitmap is a bit bizzare; it + * takes alpha >= 0x8000 to mean 'set to 1' and + * alpha < 0x8000 to mean 'set to 0'. + */ + if (xftcolor->pixel) + { + xftcolor->color.red = 0xffff; + xftcolor->color.green = 0xffff; + xftcolor->color.blue = 0xffff; + xftcolor->color.alpha = 0xffff; + } + else + { + xftcolor->color.red = 0; + xftcolor->color.green = 0; + xftcolor->color.blue = 0; + xftcolor->color.alpha = 0; + } + } + else + { + g_warning ("Using Xft rendering requires the GC argument to have a\n" + "specified colormap. If the GC was created for a drawable\n" + "with a colormap, the colormap will be set on the GC\n" + "automatically. Otherwise, a colormap must be set on it with" + "gdk_gc_set_colormap"); + } +} + +#endif + +void +_gdk_windowing_gc_get_foreground (GdkGC *gc, + GdkColor *color) +{ + GdkGCMacOSX *macosx_gc; + + g_return_if_fail (GDK_IS_GC_MACOSX (gc)); + + macosx_gc = GDK_GC_MACOSX (gc); + + _gdk_color_get_from_cgcolor(macosx_gc->stroke_color, color); +} diff --git a/gdk/macosx/gdkmacosx.h b/gdk/macosx/gdkmacosx.h new file mode 100644 index 0000000000..c14e8f7c54 --- /dev/null +++ b/gdk/macosx/gdkmacosx.h @@ -0,0 +1,55 @@ + + + +#ifndef __GDK_MACOSX_H__ +#define __GDK_MACOSX_H__ + +#include <gdk/gdk.h> +#include <Cocoa/Cocoa.h> + +#define GDK_WINDOW_NSVIEW(win) (GDK_WINDOW_IMPL_MACOSX(win)->v) + + +GdkWindow *gdk_nsview_table_lookup_for_display(GdkDisplay *display, + GdkNativeWindow anid); +void _gdk_nsview_table_insert (GdkDisplay *display, + GdkNativeWindow anid, + GdkWindow *window); + + +inline static GdkRectangle ns_to_gdkrect(NSRect r) +{ + GdkRectangle dest; + dest.x = r.origin.x; + dest.y = r.origin.y; + dest.width = r.size.width; + dest.height = r.size.height; + + return dest; +} + +inline static GdkModifierType ns_to_gdk_modifier(int modifier) +{ + GdkModifierType dest = 0; + + if (modifier & NSAlphaShiftKeyMask) { + dest |= GDK_LOCK_MASK; + } + if (modifier & NSShiftKeyMask) { + dest |= GDK_SHIFT_MASK; + } + if (modifier & NSControlKeyMask) { + dest |= GDK_CONTROL_MASK; + } + if (modifier & NSAlternateKeyMask) { + dest |= GDK_MOD1_MASK; + } + if (modifier & NSCommandKeyMask) { + dest != GDK_MOD2_MASK; + } + + return dest; +} + +#endif + diff --git a/gdk/macosx/gdkmain-macosx.c b/gdk/macosx/gdkmain-macosx.c new file mode 100644 index 0000000000..bceecbb065 --- /dev/null +++ b/gdk/macosx/gdkmain-macosx.c @@ -0,0 +1,42 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-2002 Tor Lillqvist + * Copyright (C) 2005 Hubert Figuiere + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + + + + + + +#include "gdk.h" + + + + + + + + +void +_gdk_windowing_display_set_sm_client_id (GdkDisplay *display, + const gchar *sm_client_id) +{ + g_warning("gdk_set_sm_client_id %s", sm_client_id ? sm_client_id : "NULL"); +} diff --git a/gdk/macosx/gdknsview-macosx.m b/gdk/macosx/gdknsview-macosx.m new file mode 100644 index 0000000000..88df9b40dc --- /dev/null +++ b/gdk/macosx/gdknsview-macosx.m @@ -0,0 +1,127 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include <config.h> +#include "gdkalias.h" +#include "gdkprivate-macosx.h" +#include "gdkdisplay-macosx.h" +#include <stdio.h> + +@class NSView; + +static guint gdk_nsview_hash (NSView **v); +static gboolean gdk_nsview_equal (NSView **a, NSView **b); + + +void +_gdk_nsview_table_insert (GdkDisplay *display, + NSView *v, + gpointer data) +{ + GdkDisplayMacOSX *display_macosx; + + g_return_if_fail (v != NULL); + g_return_if_fail (GDK_IS_DISPLAY (display)); + + display_macosx = GDK_DISPLAY_MACOSX (display); + + if (!display_macosx->nsview_ht) + display_macosx->nsview_ht = g_hash_table_new ((GHashFunc) gdk_nsview_hash, + (GEqualFunc) gdk_nsview_equal); + + g_hash_table_insert (display_macosx->nsview_ht, v, data); +} + +void +_gdk_xid_table_remove (GdkDisplay *display, + NSView *v) +{ + GdkDisplayMacOSX *display_macosx; + + g_return_if_fail (GDK_IS_DISPLAY(display)); + + display_macosx = GDK_DISPLAY_MACOSX(display); + + if (display_macosx->nsview_ht) + g_hash_table_remove (display_macosx->nsview_ht, &v); +} + +/** + * gdk_xid_table_lookup_for_display: + * @display: the #GdkDisplay. + * @xid: an X id. + * + * Returns the GDK object associated with the given X id. + * + * Returns: a GDK object associated with the given X id. + * + * Since: 2.2 + */ +gpointer +gdk_nsview_table_lookup_for_display (GdkDisplay *display, + NSView *v) +{ + GdkDisplayMacOSX *display_macosx; + gpointer data = NULL; + + g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); + + display_macosx = GDK_DISPLAY_MACOSX (display); + + if (display_macosx->nsview_ht) + data = g_hash_table_lookup (display_macosx->nsview_ht, &v); + + return data; +} + + +/** + * gdk_xid_table_lookup: + * @xid: an X id. + * + * Returns the Gdk object associated with the given X id. + * + * Return value: the associated Gdk object, which may be a #GdkPixmap, + * a #GdkWindow or a #GdkFont. + **/ +gpointer +gdk_nsview_table_lookup (NSView *v) +{ + return gdk_nsview_table_lookup_for_display (gdk_display_get_default (), v); +} + +static guint +gdk_nsview_hash (NSView **v) +{ + return (guint)*v; +} + +static gboolean +gdk_nsview_equal (NSView **a, + NSView **b) +{ + return (*a == *b); +} diff --git a/gdk/macosx/gdkpango-macosx.c b/gdk/macosx/gdkpango-macosx.c new file mode 100644 index 0000000000..0b18065969 --- /dev/null +++ b/gdk/macosx/gdkpango-macosx.c @@ -0,0 +1,11 @@ +#include <config.h> +#include <glib.h> +#include "gdkpango.h" + +#include <pango/pangoft2.h> + +PangoContext * +gdk_pango_context_get_for_screen (GdkScreen *screen) +{ + return pango_ft2_get_context (75.0, 75.0); +} diff --git a/gdk/macosx/gdkpixmap-macosx.h b/gdk/macosx/gdkpixmap-macosx.h new file mode 100644 index 0000000000..c0b9a1f9df --- /dev/null +++ b/gdk/macosx/gdkpixmap-macosx.h @@ -0,0 +1,70 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GDK_PIXMAP_MACOSX_H__ +#define __GDK_PIXMAP_MACOSX_H__ + +#include <gdk/macosx/gdkdrawable-macosx.h> +#include <gdk/gdkpixmap.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Pixmap implementation for MacOSX + */ + +typedef struct _GdkPixmapImplMacOSX GdkPixmapImplMacOSX; +typedef struct _GdkPixmapImplMacOSXClass GdkPixmapImplMacOSXClass; + +#define GDK_TYPE_PIXMAP_IMPL_MacOSX (gdk_pixmap_impl_macosx_get_type ()) +#define GDK_PIXMAP_IMPL_MACOSX(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXMAP_IMPL_MacOSX, GdkPixmapImplMacOSX)) +#define GDK_PIXMAP_IMPL_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXMAP_IMPL_MACOSX, GdkPixmapImplMacOSXClass)) +#define GDK_IS_PIXMAP_IMPL_MACOSX(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXMAP_IMPL_MacOSX)) +#define GDK_IS_PIXMAP_IMPL_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXMAP_IMPL_MACOSX)) +#define GDK_PIXMAP_IMPL_MACOSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXMAP_IMPL_MACOSX, GdkPixmapImplMacOSXClass)) + +struct _GdkPixmapImplMacOSX +{ + GdkDrawableImplMacOSX parent_instance; + + gint width; + gint height; + + guint is_foreign : 1; +}; + +struct _GdkPixmapImplMacOSXClass +{ + GdkDrawableImplMacOSXClass parent_class; + +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GDK_PIXMAP_MacOSX_H__ */ diff --git a/gdk/macosx/gdkprivate-macosx.h b/gdk/macosx/gdkprivate-macosx.h new file mode 100644 index 0000000000..a88ad41784 --- /dev/null +++ b/gdk/macosx/gdkprivate-macosx.h @@ -0,0 +1,217 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +/* + * Private uninstalled header defining things local to X windowing code + */ + +#ifndef __GDK_PRIVATE_MacOSX_H__ +#define __GDK_PRIVATE_MacOSX_H__ + +#include <gdk/gdkcursor.h> +#include <gdk/gdkprivate.h> +#include <gdk/macosx/gdkwindow-macosx.h> +#include <gdk/macosx/gdkpixmap-macosx.h> +#include <gdk/macosx/gdkdisplay-macosx.h> + +#include <ApplicationServices/ApplicationServices.h> + +#include "gdkinternals.h" + +#include <config.h> + +#define GDK_TYPE_GC_MACOSX (_gdk_gc_macosx_get_type ()) +#define GDK_GC_MACOSX(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_GC_MACOSX, GdkGCMacOSX)) +#define GDK_GC_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_GC_MACOSX, GdkGCMacOSXClass)) +#define GDK_IS_GC_MACOSX(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_GC_MACOSX)) +#define GDK_IS_GC_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_GC_MACOSX)) +#define GDK_GC_MACOSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_GC_MACOSX, GdkGCMacOSXClass)) + +typedef struct _GdkCursorPrivate GdkCursorPrivate; +typedef struct _GdkVisualPrivate GdkVisualPrivate; +typedef struct _GdkGCMacOSX GdkGCMacOSX; +typedef struct _GdkGCMacOSXClass GdkGCMacOSXClass; + +struct _GdkGCMacOSX +{ + GdkGC parent_instance; + + CGContextRef cggc; + GdkScreen *screen; + GdkRegion *clip_region; + guint16 dirty_mask; + guint have_clip_mask : 1; + guint depth : 8; + + GdkFill fill; + GdkBitmap *stipple; + GdkPixmap *tile; + + //cture fg_picture; + //enderColor fg_picture_color; + CGColorRef stroke_color; + CGColorRef fill_color; +}; + +struct _GdkGCMacOSXClass +{ + GdkGCClass parent_class; +}; + +struct _GdkCursorPrivate +{ + GdkCursor cursor; + Cursor xcursor; + GdkDisplay *display; +}; + +struct _GdkVisualPrivate +{ + GdkVisual visual; + //Visual *xvisual; + GdkScreen *screen; +}; + +/* +void _gdk_xid_table_insert (GdkDisplay *display, + XID *xid, + gpointer data); +void _gdk_xid_table_remove (GdkDisplay *display, + XID xid); +gint _gdk_send_xevent (GdkDisplay *display, + Window window, + gboolean propagate, + glong event_mask, + XEvent *event_send); +*/ +GType _gdk_gc_macosx_get_type (void); + +gboolean _gdk_macosx_have_render (GdkDisplay *display); +gboolean _gdk_macosx_have_render_with_trapezoids (GdkDisplay *display); + +/* +Picture _gdk_macosx_gc_get_fg_picture (GdkGC *gc); +void _gdk_gc_macosx_get_fg_xft_color (GdkGC *gc, + XftColor *xftcolor); +*/ + +GdkGC *_gdk_macosx_gc_new (GdkDrawable *drawable, + GdkGCValues *values, + GdkGCValuesMask values_mask); + +GdkImage *_gdk_macosx_copy_to_image (GdkDrawable *drawable, + GdkImage *image, + gint src_x, + gint src_y, + gint dest_x, + gint dest_y, + gint width, + gint height); +//Pixmap _gdk_macosx_image_get_shm_pixmap (GdkImage *image); + +/* Routines from gdkgeometry-macosx.c */ +void _gdk_window_init_position (GdkWindow *window); +void _gdk_window_move_resize_child (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void _gdk_window_process_expose (GdkWindow *window, + gulong serial, + GdkRectangle *area); + +void _gdk_selection_window_destroyed (GdkWindow *window); +//gboolean _gdk_selection_filter_clear_event (XSelectionClearEvent *event); + +/* +void _gdk_region_get_xrectangles (GdkRegion *region, + gint x_offset, + gint y_offset, + XRectangle **rects, + gint *n_rects); +*/ +//gboolean _gdk_moveresize_handle_event (XEvent *event); +gboolean _gdk_moveresize_configure_done (GdkDisplay *display, + GdkWindow *window); + +void _gdk_keymap_state_changed (GdkDisplay *display); +void _gdk_keymap_keys_changed (GdkDisplay *display); +gint _gdk_macosx_get_group_for_state (GdkDisplay *display, + GdkModifierType state); + +CGContextRef _gdk_macosx_gc_flush (GdkGC *gc); + +void _gdk_macosx_initialize_locale (void); + +/* +void _gdk_xgrab_check_unmap (GdkWindow *window, + gulong serial); +void _gdk_xgrab_check_destroy (GdkWindow *window); + +gboolean _gdk_macosx_display_is_root_window (GdkDisplay *display, + Window xroot_window); + +void _gdk_macosx_precache_atoms (GdkDisplay *display, + const gchar * const *atom_names, + gint n_atoms); +*/ + +void _gdk_macosx_events_init_screen (GdkScreen *screen); +void _gdk_macosx_events_uninit_screen (GdkScreen *screen); + +void _gdk_events_init (GdkDisplay *display); +void _gdk_windowing_window_init (GdkScreen *screen); +void _gdk_visual_init (GdkScreen *screen); +void _gdk_dnd_init (GdkDisplay *display); +void _gdk_windowing_image_init (GdkDisplay *display); +void _gdk_input_init (GdkDisplay *display); + +/* +PangoRenderer *_gdk_macosx_renderer_get (GdkDrawable *drawable, + GdkGC *gc); +*/ + +extern GdkDrawableClass _gdk_macosx_drawable_class; +extern gboolean _gdk_use_xshm; +extern const int _gdk_nenvent_masks; +extern const int _gdk_event_mask_table[]; +extern GdkAtom _gdk_selection_property; +extern gboolean _gdk_synchronize; + +#define GDK_PIXMAP_SCREEN(pix) (GDK_DRAWABLE_IMPL_MACOSX (((GdkPixmapObject *)pix)->impl)->screen) +#define GDK_PIXMAP_DISPLAY(pix) (GDK_SCREEN_MACOSX (GDK_PIXMAP_SCREEN (pix))->display) +#define GDK_PIXMAP_XROOTWIN(pix) (GDK_SCREEN_MACOSX (GDK_PIXMAP_SCREEN (pix))->xroot_window) +#define GDK_DRAWABLE_DISPLAY(win) (GDK_IS_WINDOW (win) ? GDK_WINDOW_DISPLAY (win) : GDK_PIXMAP_DISPLAY (win)) +#define GDK_DRAWABLE_SCREEN(win) (GDK_IS_WINDOW (win) ? GDK_WINDOW_SCREEN (win) : GDK_PIXMAP_SCREEN (win)) +#define GDK_DRAWABLE_XROOTWIN(win) (GDK_IS_WINDOW (win) ? GDK_WINDOW_XROOTWIN (win) : GDK_PIXMAP_XROOTWIN (win)) +#define GDK_SCREEN_DISPLAY(screen) (GDK_SCREEN_MACOSX (screen)->display) +#define GDK_SCREEN_XROOTWIN(screen) (GDK_SCREEN_MACOSX (screen)->xroot_window) +#define GDK_WINDOW_SCREEN(win) (GDK_DRAWABLE_IMPL_MACOSX (((GdkWindowObject *)win)->impl)->screen) +#define GDK_WINDOW_DISPLAY(win) (GDK_SCREEN_MACOSX (GDK_WINDOW_SCREEN (win))->display) +#define GDK_WINDOW_XROOTWIN(win) (GDK_SCREEN_MACOSX (GDK_WINDOW_SCREEN (win))->xroot_window) +#define GDK_GC_DISPLAY(gc) (GDK_SCREEN_DISPLAY (GDK_GC_MACOSX(gc)->screen)) + +#endif /* __GDK_PRIVATE_MACOSX_H__ */ diff --git a/gdk/macosx/gdkscreen-macosx.h b/gdk/macosx/gdkscreen-macosx.h new file mode 100644 index 0000000000..3b22473405 --- /dev/null +++ b/gdk/macosx/gdkscreen-macosx.h @@ -0,0 +1,70 @@ +/* + * gdkscreen-macosx.h + * + * Copyright 2001 Sun Microsystems Inc. + * + * Erwann Chenede <erwann.chenede@sun.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GDK_SCREEN_MACOSX_H__ +#define __GDK_SCREEN_MACOSX_H__ + +#include "gdkprivate-macosx.h" +//#include "xsettings-client.h" +#include <gdk/gdkscreen.h> +#include <gdk/gdkvisual.h> + +G_BEGIN_DECLS + +typedef struct _GdkScreenMacOSX GdkScreenMacOSX; +typedef struct _GdkScreenMacOSXClass GdkScreenMacOSXClass; + +#define GDK_TYPE_SCREEN_MACOSX (_gdk_screen_macosx_get_type ()) +#define GDK_SCREEN_MACOSX(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SCREEN_MACOSX, GdkScreenMacOSX)) +#define GDK_SCREEN_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SCREEN_MACOSX, GdkScreenMacOSXClass)) +#define GDK_IS_SCREEN_MACOSX(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SCREEN_MACOSX)) +#define GDK_IS_SCREEN_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SCREEN_MACOSX)) +#define GDK_SCREEN_MACOSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SCREEN_MACOSX, GdkScreenMacOSXClass)) + +@class NSEvent; +@class NSScreen; + +struct _GdkScreenMacOSX +{ + GdkScreen parent_instance; + + GdkDisplay *display; + GdkWindow *root_window; + GdkColormap *default_colormap; +}; + +struct _GdkScreenMacOSXClass +{ + GdkScreenClass parent_class; +}; + +GType _gdk_screen_macosx_get_type (void); +GdkScreen * _gdk_macosx_screen_new (GdkDisplay *display, + NSScreen *screen); + +void _gdk_macosx_screen_size_changed (GdkScreen *screen, + NSEvent *event); + +G_END_DECLS + +#endif /* __GDK_SCREEN_MacOSX_H__ */ diff --git a/gdk/macosx/gdkscreen-macosx.m b/gdk/macosx/gdkscreen-macosx.m new file mode 100644 index 0000000000..5aa2762075 --- /dev/null +++ b/gdk/macosx/gdkscreen-macosx.m @@ -0,0 +1,452 @@ +/* + * gdkscreen-macosx.c + * + * Copyright 2001 Sun Microsystems Inc. + * Copyright 2005 Hubert Figuiere + * + * Hubert Figuiere <hub@figuiere.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> + +#include <Cocoa/Cocoa.h> + +#include <glib.h> +#include "gdkmacosx.h" +#include "gdkalias.h" +#include "gdkscreen.h" +#include "gdkscreen-macosx.h" +#include "gdkdisplay.h" +#include "gdkdisplay-macosx.h" + + +static void gdk_screen_macosx_class_init (GdkScreenMacOSXClass *klass); +static void gdk_screen_macosx_dispose (GObject *object); +static void gdk_screen_macosx_finalize (GObject *object); +static void init_xinerama_support (GdkScreen *screen); +static void init_randr_support (GdkScreen *screen); + +enum +{ + WINDOW_MANAGER_CHANGED, + LAST_SIGNAL +}; + +static gpointer parent_class = NULL; +static guint signals[LAST_SIGNAL] = { 0 }; + +GType +_gdk_screen_macosx_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (GdkScreenMacOSXClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gdk_screen_macosx_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GdkScreenMacOSX), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + }; + object_type = g_type_register_static (GDK_TYPE_SCREEN, + "GdkScreenMacOSX", + &object_info, 0); + } + return object_type; +} + +static void +gdk_screen_macosx_class_init (GdkScreenMacOSXClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gdk_screen_macosx_dispose; + object_class->finalize = gdk_screen_macosx_finalize; + + parent_class = g_type_class_peek_parent (klass); +} + +/** + * gdk_screen_get_display: + * @screen: a #GdkScreen + * + * Gets the display to which the @screen belongs. + * + * Returns: the display to which @screen belongs + * + * Since: 2.2 + **/ +GdkDisplay * +gdk_screen_get_display (GdkScreen *screen) +{ + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + + return GDK_SCREEN_MACOSX (screen)->display; +} +/** + * gdk_screen_get_width: + * @screen: a #GdkScreen + * + * Gets the width of @screen in pixels + * + * Returns: the width of @screen in pixels. + * + * Since: 2.2 + **/ +gint +gdk_screen_get_width (GdkScreen *screen) +{ + NSArray *all_screens; + NSRect frame; + NSScreen *ns_screen; + NSEnumerator *iter; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), 0); + + frame = NSMakeRect(0,0,0,0); + + all_screens = [NSScreen screens]; + iter = [all_screens objectEnumerator]; + + while(ns_screen = [iter nextObject]) + { + frame = NSUnionRect(frame, [ns_screen frame]); + } + + return frame.size.width; +} + +/** + * gdk_screen_get_height: + * @screen: a #GdkScreen + * + * Gets the height of @screen in pixels + * + * Returns: the height of @screen in pixels. + * + * Since: 2.2 + **/ +gint +gdk_screen_get_height (GdkScreen *screen) +{ + NSArray *all_screens; + NSRect frame; + NSScreen *ns_screen; + NSEnumerator *iter; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), 0); + + frame = NSMakeRect(0,0,0,0); + + all_screens = [NSScreen screens]; + iter = [all_screens objectEnumerator]; + + while(ns_screen = [iter nextObject]) + { + frame = NSUnionRect(frame, [ns_screen frame]); + } + + return frame.size.height; +} + + +static NSSize +_gdk_screen_get_dpi(GdkScreen *screen) +{ + NSSize s; + NSScreen *ns_screen = [NSScreen mainScreen]; + + NSDictionary *props = [ns_screen deviceDescription]; + + s = [[props objectForKey:NSDeviceResolution] size]; + + return s; +} +/* +@"NSScreenNumber" +*/ + +/** + * gdk_screen_get_width_mm: + * @screen: a #GdkScreen + * + * Gets the width of @screen in millimeters. + * Note that on some X servers this value will not be correct. + * + * Returns: the width of @screen in pixels. + * + * Since: 2.2 + **/ +gint +gdk_screen_get_width_mm (GdkScreen *screen) +{ + NSSize s; + g_return_val_if_fail (GDK_IS_SCREEN (screen), 0); + + s = _gdk_screen_get_dpi(screen); + return gdk_screen_get_width(screen) / (s.width / 25.4); +} + +/** + * gdk_screen_get_height_mm: + * @screen: a #GdkScreen + * + * Returns the height of @screen in millimeters. + * Note that on some X servers this value will not be correct. + * + * Returns: the heigth of @screen in pixels. + * + * Since: 2.2 + **/ +gint +gdk_screen_get_height_mm (GdkScreen *screen) +{ + NSSize s; + g_return_val_if_fail (GDK_IS_SCREEN (screen), 0); + + s = _gdk_screen_get_dpi(screen); + return gdk_screen_get_height(screen) / (s.height / 25.4); +} + +/** + * gdk_screen_get_number: + * @screen: a #GdkScreen + * + * Gets the index of @screen among the screens in the display + * to which it belongs. (See gdk_screen_get_display()) + * + * Returns: the index + * + * Since: 2.2 + **/ +gint +gdk_screen_get_number (GdkScreen *screen) +{ + g_return_val_if_fail (GDK_IS_SCREEN (screen), 0); + + return 0; +} + +/** + * gdk_screen_get_root_window: + * @screen: a #GdkScreen + * + * Gets the root window of @screen. + * + * Returns: the root window + * + * Since: 2.2 + **/ +GdkWindow * +gdk_screen_get_root_window (GdkScreen *screen) +{ + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + + // FIXME + + return NULL; +} + +/** + * gdk_screen_get_default_colormap: + * @screen: a #GdkScreen + * + * Gets the default colormap for @screen. + * + * Returns: the default #GdkColormap. + * + * Since: 2.2 + **/ +GdkColormap * +gdk_screen_get_default_colormap (GdkScreen *screen) +{ + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + + return GDK_SCREEN_MACOSX (screen)->default_colormap; +} + +/** + * gdk_screen_set_default_colormap: + * @screen: a #GdkScreen + * @colormap: a #GdkColormap + * + * Sets the default @colormap for @screen. + * + * Since: 2.2 + **/ +void +gdk_screen_set_default_colormap (GdkScreen *screen, + GdkColormap *colormap) +{ + GdkColormap *old_colormap; + + g_return_if_fail (GDK_IS_SCREEN (screen)); + g_return_if_fail (GDK_IS_COLORMAP (colormap)); + + old_colormap = GDK_SCREEN_MACOSX (screen)->default_colormap; + + GDK_SCREEN_MACOSX (screen)->default_colormap = g_object_ref (colormap); + + if (old_colormap) + g_object_unref (old_colormap); +} + +static void +gdk_screen_macosx_dispose (GObject *object) +{ + GdkScreenMacOSX *screen_macosx = GDK_SCREEN_MACOSX (object); + + //_gdk_macosx_events_uninit_screen (GDK_SCREEN (object)); + + g_object_unref (screen_macosx->default_colormap); + screen_macosx->default_colormap = NULL; + + screen_macosx->root_window = NULL; + + screen_macosx->display = NULL; + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gdk_screen_macosx_finalize (GObject *object) +{ + GdkScreenMacOSX *screen_macosx = GDK_SCREEN_MACOSX (object); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +/** + * gdk_screen_get_n_monitors: + * @screen: a #GdkScreen. + * + * Returns the number of monitors which @screen consists of. + * + * Returns: number of monitors which @screen consists of. + * + * Since: 2.2 + **/ +gint +gdk_screen_get_n_monitors (GdkScreen *screen) +{ + g_return_val_if_fail (GDK_IS_SCREEN (screen), 0); + return [[NSScreen screens] count]; +} + +/** + * gdk_screen_get_monitor_geometry: + * @screen : a #GdkScreen. + * @monitor_num: the monitor number. + * @dest : a #GdkRectangle to be filled with the monitor geometry + * + * Retrieves the #GdkRectangle representing the size and position of + * the individual monitor within the entire screen area. + * + * Note that the size of the entire screen area can be retrieved via + * gdk_screen_get_width() and gdk_screen_get_height(). + * + * Since: 2.2 + **/ +void +gdk_screen_get_monitor_geometry (GdkScreen *screen, + gint monitor_num, + GdkRectangle *dest) +{ + NSRect rect; + + g_return_if_fail (GDK_IS_SCREEN (screen)); +/* g_return_if_fail (monitor_num < GDK_SCREEN_MACOSX (screen)->num_monitors); + g_return_if_fail (monitor_num >= 0);*/ + + rect = [[[NSScreen screens] objectAtIndex:monitor_num] frame]; + + *dest = ns_to_gdkrect(rect); +} + + + +GdkScreen * +_gdk_macosx_screen_new (GdkDisplay *display, + NSScreen *screen) +{ + GdkScreen *gscreen; + GdkScreenMacOSX *screen_macosx; + GdkDisplayMacOSX *display_macosx = GDK_DISPLAY_MACOSX (display); + + gscreen = g_object_new (GDK_TYPE_SCREEN_MACOSX, NULL); + + screen_macosx = GDK_SCREEN_MACOSX (gscreen); + screen_macosx->display = display; + screen_macosx->default_colormap = NULL; +// screen_macosx->xroot_window = RootWindow (display_macosx->xdisplay,screen_number); + + _gdk_visual_init (gscreen); + _gdk_windowing_window_init (gscreen); + + return gscreen; +} + + + +/** + * _gdk_windowing_substitute_screen_number: + * @display_name : The name of a display, in the form used by + * gdk_display_open (). If %NULL a default value + * will be used. On MacOSX, this is derived from the DISPLAY + * environment variable. + * @screen_number : The number of a screen within the display + * referred to by @display_name. + * + * Modifies a @display_name to make @screen_number the default + * screen when the display is opened. + * + * Return value: a newly allocated string holding the resulting + * display name. Free with g_free(). + */ +gchar * +_gdk_windowing_substitute_screen_number (const gchar *display_name, + gint screen_number) +{ + return g_strdup (display_name); +} + +/** + * gdk_screen_make_display_name: + * @screen: a #GdkScreen + * + * Determines the name to pass to gdk_display_open() to get + * a #GdkDisplay with this screen as the default screen. + * + * Return value: a newly allocated string, free with g_free() + * + * Since: 2.2 + **/ +gchar * +gdk_screen_make_display_name (GdkScreen *screen) +{ + return g_strdup (""); +} diff --git a/gdk/macosx/gdkwindow-macosx.h b/gdk/macosx/gdkwindow-macosx.h new file mode 100644 index 0000000000..cfcbd25530 --- /dev/null +++ b/gdk/macosx/gdkwindow-macosx.h @@ -0,0 +1,106 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GDK_WINDOW_MACOSX_H__ +#define __GDK_WINDOW_MACOSX_H__ + +#include <gdk/macosx/gdkdrawable-macosx.h> + +G_BEGIN_DECLS + +typedef struct _GdkToplevelMacOSX GdkToplevelMacOSX; +typedef struct _GdkWindowImplMacOSX GdkWindowImplMacOSX; +typedef struct _GdkWindowImplMacOSXClass GdkWindowImplMacOSXClass; +typedef struct _GdkMacPositionInfo GdkMacPositionInfo; + +struct _GdkMacPositionInfo +{ + gint x; + gint y; + gint width; + gint height; + gint x_offset; /* Offsets to add to X coordinates within window */ + gint y_offset; /* to get GDK coodinates within window */ + guint big : 1; + guint mapped : 1; + guint no_bg : 1; /* Set when the window background is temporarily + * unset during resizing and scaling */ + GdkRectangle clip_rect; /* visible rectangle of window */ +}; + + +/* Window implementation for MacOSX + */ + +#define GDK_TYPE_WINDOW_IMPL_MACOSX (gdk_window_impl_macosx_get_type ()) +#define GDK_WINDOW_IMPL_MACOSX(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WINDOW_IMPL_MACOSX, GdkWindowImplMacOSX)) +#define GDK_WINDOW_IMPL_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW_IMPL_MACOSX, GdkWindowImplMacOSXClass)) +#define GDK_IS_WINDOW_IMPL_MACOSX(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WINDOW_IMPL_MACOSX)) +#define GDK_IS_WINDOW_IMPL_MACOSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WINDOW_IMPL_MACOSX)) +#define GDK_WINDOW_IMPL_MACOSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW_IMPL_MACOSX, GdkWindowImplMacOSXClass)) + +@class NSWindow; +@class NSView; + +struct _GdkWindowImplMacOSX +{ + GdkDrawableImplMacOSX parent_instance; + + gint width; + gint height; + + + GdkMacPositionInfo position_info; + GdkToplevelMacOSX *toplevel; /* Toplevel-specific information */ + gint8 toplevel_window_type; + NSView *v; +}; + +struct _GdkWindowImplMacOSXClass +{ + GdkDrawableImplMacOSXClass parent_class; +}; + +struct _GdkToplevelMacOSX +{ + NSWindow *w; +}; + +GType gdk_window_impl_macosx_get_type (void); + +void gdk_macosx_window_set_user_time (GdkWindow *window, + guint32 timestamp); + +GdkToplevelMacOSX *_gdk_macosx_window_get_toplevel (GdkWindow *window); +void _gdk_macosx_window_tmp_unset_bg (GdkWindow *window, + gboolean recurse); +void _gdk_macosx_window_tmp_reset_bg (GdkWindow *window, + gboolean recurse); + + +G_END_DECLS + +#endif /* __GDK_WINDOW_MACOSX_H__ */ diff --git a/gdk/macosx/gdkwindow-macosx.m b/gdk/macosx/gdkwindow-macosx.m new file mode 100644 index 0000000000..c1baa4e99e --- /dev/null +++ b/gdk/macosx/gdkwindow-macosx.m @@ -0,0 +1,5540 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ +/* + * Mac Port by Hubert Figuiere <hfiguiere@teaser.fr> + */ + +#include <config.h> + +#include <unistd.h> + +#include "gdkalias.h" +#include "gdk.h" + +#include "gdkwindow.h" +#include "gdkmacosx.h" +//#include "gdkinputprivate.h" +#include "gdkdisplay-macosx.h" +#include "gdkscreen-macosx.h" +//#include "gdkprivate-x11.h" +#include "gdkregion.h" +#include "gdkinternals.h" +#include "gdkwindow-macosx.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <Cocoa/Cocoa.h> + + +static GdkWindow *_gdk_parent_root = NULL; + +/* Forward declarations */ +static void gdk_window_set_static_win_gravity (GdkWindow *window, + gboolean on); +static gboolean gdk_window_have_shape_ext (GdkDisplay *display); +static gboolean gdk_window_icon_name_set (GdkWindow *window); +static void gdk_window_add_colormap_windows (GdkWindow *window); + + +static GdkColormap* gdk_window_impl_macosx_get_colormap (GdkDrawable *drawable); +static void gdk_window_impl_macosx_set_colormap (GdkDrawable *drawable, + GdkColormap *cmap); +static void gdk_window_impl_macosx_get_size (GdkDrawable *drawable, + gint *width, + gint *height); +static GdkRegion* gdk_window_impl_macosx_get_visible_region (GdkDrawable *drawable); +static void gdk_window_impl_macosx_init (GdkWindowImplMacOSX *window); +static void gdk_window_impl_macosx_class_init (GdkWindowImplMacOSXClass *klass); +static void gdk_window_impl_macosx_finalize (GObject *object); + +static gpointer parent_class = NULL; + +#define WINDOW_IS_TOPLEVEL(window) \ + (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \ + GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN) + + +GType +gdk_window_impl_macosx_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (GdkWindowImplMacOSXClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gdk_window_impl_macosx_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GdkWindowImplMacOSX), + 0, /* n_preallocs */ + (GInstanceInitFunc) gdk_window_impl_macosx_init, + }; + + object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_MACOSX, + "GdkWindowImplMacOSX", + &object_info, 0); + } + + return object_type; +} + +GType +_gdk_window_impl_get_type (void) +{ + return gdk_window_impl_macosx_get_type (); +} + +static void +gdk_window_impl_macosx_init (GdkWindowImplMacOSX *impl) +{ + impl->width = 1; + impl->height = 1; + impl->toplevel_window_type = -1; +} + +GdkToplevelMacOSX * +_gdk_macosx_window_get_toplevel (GdkWindow *window) +{ + GdkWindowObject *private; + GdkWindowImplMacOSX *impl; + + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + + if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD) + return NULL; + + private = (GdkWindowObject *)window; + impl = GDK_WINDOW_IMPL_MACOSX (private->impl); + + if (!impl->toplevel) + impl->toplevel = g_new0 (GdkToplevelMacOSX, 1); + + return impl->toplevel; +} + +static void +gdk_window_impl_macosx_class_init (GdkWindowImplMacOSXClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = gdk_window_impl_macosx_finalize; + + drawable_class->set_colormap = gdk_window_impl_macosx_set_colormap; + drawable_class->get_colormap = gdk_window_impl_macosx_get_colormap; + drawable_class->get_size = gdk_window_impl_macosx_get_size; + + /* Visible and clip regions are the same */ + drawable_class->get_clip_region = gdk_window_impl_macosx_get_visible_region; + drawable_class->get_visible_region = gdk_window_impl_macosx_get_visible_region; +} + +static void +gdk_window_impl_macosx_finalize (GObject *object) +{ + GdkWindowObject *wrapper; + GdkDrawableImplMacOSX *draw_impl; + GdkWindowImplMacOSX *window_impl; + + g_return_if_fail (GDK_IS_WINDOW_IMPL_MACOSX (object)); + + draw_impl = GDK_DRAWABLE_IMPL_MACOSX (object); + window_impl = GDK_WINDOW_IMPL_MACOSX (object); + + wrapper = (GdkWindowObject*) draw_impl->wrapper; + + if (window_impl->toplevel) + g_free (window_impl->toplevel); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +#if 0 + +static void +tmp_unset_bg (GdkWindow *window) +{ + GdkWindowImplMacOSX *impl; + GdkWindowObject *obj; + + obj = (GdkWindowObject *) window; + impl = GDK_WINDOW_IMPL_MACOSX (obj->impl); + + /* For windows without EXPOSURE_MASK, we can't do this + * unsetting because such windows depend on the drawing + * that the X server is going to do + */ + if (!(obj->event_mask & GDK_EXPOSURE_MASK)) + return; + + impl->position_info.no_bg = TRUE; + +// if (obj->bg_pixmap != GDK_NO_BG) +// XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window), +// GDK_DRAWABLE_XID (window), None); +} + + +void +_gdk_macosx_window_tmp_unset_bg (GdkWindow *window, + gboolean recurse) +{ + GdkWindowObject *private; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *)window; + + if (private->input_only || private->destroyed || + (private->window_type != GDK_WINDOW_ROOT && + !GDK_WINDOW_IS_MAPPED (window))) + { + return; + } + + if (private->window_type != GDK_WINDOW_ROOT && + private->window_type != GDK_WINDOW_FOREIGN) + { + tmp_unset_bg (window); + } + + if (recurse) + { + GList *l; + + for (l = private->children; l != NULL; l = l->next) + _gdk_macosx_window_tmp_unset_bg (l->data, TRUE); + } +} + +#endif + +static GdkColormap* +gdk_window_impl_macosx_get_colormap (GdkDrawable *drawable) +{ + GdkDrawableImplMacOSX *drawable_impl; + + drawable_impl = GDK_DRAWABLE_IMPL_MACOSX (drawable); + + if (!((GdkWindowObject *) drawable_impl->wrapper)->input_only && + drawable_impl->colormap == NULL) + { + drawable_impl->colormap = gdk_screen_get_system_colormap (gdk_drawable_get_screen (drawable)); + g_object_ref (drawable_impl->colormap); + } + + return drawable_impl->colormap; +} + + +static void +gdk_window_impl_macosx_set_colormap (GdkDrawable *drawable, + GdkColormap *cmap) +{ + GdkWindowImplMacOSX *impl; + GdkDrawableImplMacOSX *draw_impl; + + g_return_if_fail (GDK_IS_WINDOW_IMPL_MACOSX (drawable)); + + impl = GDK_WINDOW_IMPL_MACOSX (drawable); + draw_impl = GDK_DRAWABLE_IMPL_MACOSX (drawable); + + if (cmap && GDK_WINDOW_DESTROYED (draw_impl->wrapper)) + return; + + /* chain up */ + GDK_DRAWABLE_CLASS (parent_class)->set_colormap (drawable, cmap); +} + + +static void +gdk_window_impl_macosx_get_size (GdkDrawable *drawable, + gint *width, + gint *height) +{ + g_return_if_fail (GDK_IS_WINDOW_IMPL_MACOSX (drawable)); + + if (width) + *width = GDK_WINDOW_IMPL_MACOSX (drawable)->width; + if (height) + *height = GDK_WINDOW_IMPL_MACOSX (drawable)->height; +} + +static GdkRegion* +gdk_window_impl_macosx_get_visible_region (GdkDrawable *drawable) +{ + GdkWindowImplMacOSX *impl = GDK_WINDOW_IMPL_MACOSX (drawable); + GdkRectangle result_rect; + + result_rect.x = 0; + result_rect.y = 0; + result_rect.width = impl->width; + result_rect.height = impl->height; + + gdk_rectangle_intersect (&result_rect, &impl->position_info.clip_rect, &result_rect); + + return gdk_region_rectangle (&result_rect); +} + +void +_gdk_windowing_window_init (GdkScreen * screen) +{ + GdkWindowObject *private; + GdkWindowImplMacOSX *impl; + GdkDrawableImplMacOSX *draw_impl; + GdkScreenMacOSX *screen_macosx; + NSRect *screen_frame; + + screen_macosx = GDK_SCREEN_MACOSX (screen); + + g_assert (screen_macosx->root_window == NULL); + + gdk_screen_set_default_colormap (screen, + gdk_screen_get_system_colormap (screen)); + + screen_macosx->root_window = g_object_new (GDK_TYPE_WINDOW, NULL); + private = (GdkWindowObject *)screen_macosx->root_window; + impl = GDK_WINDOW_IMPL_MACOSX (private->impl); + draw_impl = GDK_DRAWABLE_IMPL_MACOSX (private->impl); + + impl->v = NULL; + + /* FIXME */ + _gdk_window_init_position (GDK_WINDOW (private)); +} + +#if 0 +static const gchar * +get_default_title (void) +{ + const char *title; + + title = g_get_application_name (); + if (!title) + title = g_get_prgname (); + + return title; +} + + +/** + * gdk_window_new: + * @parent: a #GdkWindow, or %NULL to create the window as a child of + * the default root window for the default display. + * @attributes: attributes of the new window + * @attributes_mask: mask indicating which fields in @attributes are valid + * + * Creates a new #GdkWindow using the attributes from + * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for + * more details. Note: to use this on displays other than the default + * display, @parent must be specified. + * + * Return value: the new #GdkWindow + **/ +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowObject *private; + GdkWindowImplMacOSX *impl; + GdkDrawableImplMacOSX *draw_impl; + GdkScreenMacOSX *screen_macosx; + GdkScreen *screen; + + GdkVisual *visual; + + int x, y, depth; + + unsigned int class; + const char *title; + int i; + + NSRect bounds; + NSWindow *w; + GdkNSView *v; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + { + GDK_NOTE (MULTIHEAD, + g_warning ("gdk_window_new(): no parent specified reverting to parent = default root window")); + + screen = gdk_screen_get_default (); + parent = gdk_screen_get_root_window (screen); + } + else + screen = gdk_drawable_get_screen (parent); + + screen_macosx = GDK_SCREEN_MACOSX (screen); + + g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL); + + if (GDK_WINDOW_DESTROYED (parent)) + return NULL; + + window = g_object_new (GDK_TYPE_WINDOW, NULL); + private = (GdkWindowObject *)window; + impl = GDK_WINDOW_IMPL_MACOSX (private->impl); + draw_impl = GDK_DRAWABLE_IMPL_MACOSX (private->impl); + draw_impl->wrapper = GDK_DRAWABLE (window); + + draw_impl->screen = screen; + + /* Windows with a foreign parent are treated as if they are children + * of the root window, except for actual creation. + */ + if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN) + parent = gdk_screen_get_root_window (screen); + + private->parent = (GdkWindowObject *)parent; + + private->accept_focus = TRUE; + private->focus_on_map = TRUE; + + xattributes_mask = 0; + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = 0; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else + y = 0; + + private->x = x; + private->y = y; + impl->width = (attributes->width > 1) ? (attributes->width) : (1); + impl->height = (attributes->height > 1) ? (attributes->height) : (1); + + if (attributes->wclass == GDK_INPUT_ONLY) + { + /* Backwards compatiblity - we've always ignored + * attributes->window_type for input-only windows + * before + */ + if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT) + private->window_type = GDK_WINDOW_TEMP; + else + private->window_type = GDK_WINDOW_CHILD; + } + else + private->window_type = attributes->window_type; + + _gdk_window_init_position (GDK_WINDOW (private)); + if (impl->position_info.big) + private->guffaw_gravity = TRUE; + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_screen_get_system_visual (screen); + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + xattributes.event_mask = StructureNotifyMask | PropertyChangeMask; + for (i = 0; i < _gdk_nenvent_masks; i++) + { + if (attributes->event_mask & (1 << (i + 1))) + xattributes.event_mask |= _gdk_event_mask_table[i]; + } + private->event_mask = attributes->event_mask; + + if (xattributes.event_mask) + xattributes_mask |= CWEventMask; + + if (attributes_mask & GDK_WA_NOREDIR) + { + xattributes.override_redirect = + (attributes->override_redirect == FALSE)?False:True; + xattributes_mask |= CWOverrideRedirect; + } + else + xattributes.override_redirect = False; + + impl->override_redirect = xattributes.override_redirect; + + if (private->parent && private->parent->guffaw_gravity) + { + xattributes.win_gravity = StaticGravity; + xattributes_mask |= CWWinGravity; + } + + /* Sanity checks */ + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT) + { + g_warning (G_STRLOC "Toplevel windows must be created as children of\n" + "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN"); + xparent = GDK_SCREEN_XROOTWIN (screen); + } + case GDK_WINDOW_CHILD: + break; + default: + g_warning (G_STRLOC "cannot make windows of type %d", private->window_type); + return NULL; + } + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + class = InputOutput; + depth = visual->depth; + + private->input_only = FALSE; + private->depth = depth; + + if (attributes_mask & GDK_WA_COLORMAP) + { + draw_impl->colormap = attributes->colormap; + g_object_ref (attributes->colormap); + } + else + { + if ((((GdkVisualPrivate *)gdk_screen_get_system_visual (screen))->xvisual) == xvisual) + { + draw_impl->colormap = gdk_screen_get_system_colormap (screen); + g_object_ref (draw_impl->colormap); + } + else + { + draw_impl->colormap = gdk_colormap_new (visual, FALSE); + } + } + + private->bg_color.pixel = BlackPixel (xdisplay, screen_macosx->screen_num); + xattributes.background_pixel = private->bg_color.pixel; + + private->bg_pixmap = NULL; + + xattributes.border_pixel = BlackPixel (xdisplay, screen_macosx->screen_num); + xattributes_mask |= CWBorderPixel | CWBackPixel; + + if (private->guffaw_gravity) + xattributes.bit_gravity = StaticGravity; + else + xattributes.bit_gravity = NorthWestGravity; + + xattributes_mask |= CWBitGravity; + + xattributes.colormap = GDK_COLORMAP_XCOLORMAP (draw_impl->colormap); + xattributes_mask |= CWColormap; + + if (private->window_type == GDK_WINDOW_TEMP) + { + xattributes.save_under = True; + xattributes.override_redirect = True; + xattributes.cursor = None; + xattributes_mask |= CWSaveUnder | CWOverrideRedirect; + + impl->override_redirect = TRUE; + } + } + else + { + depth = 0; + private->depth = 0; + class = InputOnly; + private->input_only = TRUE; + draw_impl->colormap = gdk_screen_get_system_colormap (screen); + g_object_ref (draw_impl->colormap); + } + + // FIXME, map Gdk to Cocoa window styles... + unsigned int style_mask = NSBorderlessWindowMask; + + bounds = NSMakeRect(impl->position_info.x, + NSHeight([[NSScreen mainScreen] frame]) - + impl->position_info.y - impl->position_info.height, + impl->position_info.width, impl->position_info.height); + + + w = [[NSWindow alloc] initWithContentRect:bounds + styleMask:theStyleMask + backing:NSBackingStoreBuffered + defer:YES]; + window_impl->w = w; + + [w setBackgroundColor:[NSColor clearColor]]; // erase transparent + [w setAlphaValue:1.0]; // draw opaque + [w setOpaque:YES]; // changed when window is shaped + + [w useOptimizedDrawing:YES]; // Has no overlapping sub-views + [w setAutodisplay:NO]; // See comment above + [w disableFlushWindow]; // We do all the flushing manually + [w setHasShadow:YES]; // All windows have shadows + [w setReleasedWhenClosed:YES]; // Default, but we want to be sure + + v = [[GdkNSView alloc] initWithFrame:bounds]; + [w setContentView:v]; + [w setInitialFirstResponder:v]; + + draw_impl->v = v; + +// xid = draw_impl->xid = XCreateWindow (xdisplay, xparent, +// impl->position_info.x, impl->position_info.y, +// impl->position_info.width, impl->position_info.height, +// 0, depth, class, xvisual, +// xattributes_mask, &xattributes); + + g_object_ref (window); + _gdk_nsview_table_insert(screen_macosx->display, &draw_impl->v, window); + + gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? + (attributes->cursor) : + NULL)); + + if (private->parent) + private->parent->children = g_list_prepend (private->parent->children, window); + + switch (GDK_WINDOW_TYPE (private)) + { + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_TEMP: + if (attributes_mask & GDK_WA_TITLE) + title = attributes->title; + else + title = get_default_title (); + + gdk_window_set_title (window, title); + + if (attributes_mask & GDK_WA_WMCLASS) + { + class_hint = XAllocClassHint (); + class_hint->res_name = attributes->wmclass_name; + class_hint->res_class = attributes->wmclass_class; + XSetClassHint (xdisplay, xid, class_hint); + XFree (class_hint); + } + + setup_toplevel_window (window, parent); + break; + + case GDK_WINDOW_CHILD: + if ((attributes->wclass == GDK_INPUT_OUTPUT) && + (draw_impl->colormap != gdk_screen_get_system_colormap (screen)) && + (draw_impl->colormap != gdk_drawable_get_colormap (gdk_window_get_toplevel (window)))) + { + GDK_NOTE (MISC, g_message ("adding colormap window\n")); + gdk_window_add_colormap_windows (window); + } + break; + + default: + break; + } + + return window; +} + +static GdkEventMask +x_event_mask_to_gdk_event_mask (long mask) +{ + GdkEventMask event_mask = 0; + int i; + + for (i = 0; i < _gdk_nenvent_masks; i++) + { + if (mask & _gdk_event_mask_table[i]) + event_mask |= 1 << (i + 1); + } + + return event_mask; +} +#endif + +/** + * gdk_window_foreign_new_for_display: + * @display: the #GdkDisplay where the window handle comes from. + * @anid: a native window handle. + * + * Wraps a native window in a #GdkWindow. + * This may fail if the window has been destroyed. If the window + * was already known to GDK, a new reference to the existing + * #GdkWindow is returned. + * + * For example in the X backend, a native window handle is an Xlib + * <type>XID</type>. + * + * Return value: a #GdkWindow wrapper for the native window or + * %NULL if the window has been destroyed. The wrapper will be + * newly created, if one doesn't exist already. + * + * Since: 2.2 + **/ +GdkWindow * +gdk_window_foreign_new_for_display (GdkDisplay *display, + GdkNativeWindow anid) +{ + GdkWindow *window; + GdkWindowObject *private; + GdkWindowImplMacOSX *impl; + GdkDrawableImplMacOSX *draw_impl; + GdkDisplayMacOSX *display_macosx; + NSRect frame; + NSWindowDepth wdepth; + + guint nchildren; + gboolean result; + + g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); + + display_macosx = GDK_DISPLAY_MACOSX (display); + + if ((window = gdk_nsview_table_lookup_for_display(display, anid)) != NULL) + return g_object_ref (window); + + window = g_object_new (GDK_TYPE_WINDOW, NULL); + private = (GdkWindowObject *)window; + impl = GDK_WINDOW_IMPL_MACOSX (private->impl); + draw_impl = GDK_DRAWABLE_IMPL_MACOSX (private->impl); + draw_impl->wrapper = GDK_DRAWABLE (window); + + private->parent = gdk_nsview_table_lookup_for_display(display, [(NSView *)anid superview]); + + if (!private->parent || GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_FOREIGN) + private->parent = _gdk_parent_root; + + private->parent->children = g_list_prepend (private->parent->children, window); + + impl->v = anid; + + frame = [impl->v frame]; + private->x = frame.origin.x; + private->y = frame.origin.y; + impl->width = frame.size.width; + impl->height = frame.size.height; + private->window_type = GDK_WINDOW_FOREIGN; + private->destroyed = FALSE; + + // FIXME + private->event_mask = 0; //x_event_mask_to_gdk_event_mask (attrs.your_event_mask); +/* + if (attrs.map_state == IsUnmapped) + private->state = GDK_WINDOW_STATE_WITHDRAWN; + else */ + private->state = 0; + + wdepth = [[(NSView *)anid window] depthLimit]; + private->depth = NSBitsPerPixelFromDepth(wdepth); + + _gdk_window_init_position (GDK_WINDOW (private)); + + g_object_ref (window); + _gdk_nsview_table_insert(display, GDK_WINDOW_NSVIEW (window), window); + return window; +} + +#if 0 +/** + * gdk_window_lookup_for_display: + * @display: the #GdkDisplay corresponding to the window handle + * @anid: a native window handle. + * + * Looks up the #GdkWindow that wraps the given native window handle. + * + * For example in the X backend, a native window handle is an Xlib + * <type>XID</type>. + * + * Return value: the #GdkWindow wrapper for the native window, + * or %NULL if there is none. + * + * Since: 2.2 + **/ +GdkWindow * +gdk_window_lookup_for_display (GdkDisplay *display, GdkNativeWindow anid) +{ + return (GdkWindow*) gdk_xid_table_lookup_for_display (display, anid); +} + +/** + * gdk_window_lookup: + * @anid: a native window handle. + * + * Looks up the #GdkWindow that wraps the given native window handle. + * + * For example in the X backend, a native window handle is an Xlib + * <type>XID</type>. + * + * Return value: the #GdkWindow wrapper for the native window, + * or %NULL if there is none. + **/ +GdkWindow * +gdk_window_lookup (GdkNativeWindow anid) +{ + return (GdkWindow*) gdk_xid_table_lookup (anid); +} + +static void +gdk_toplevel_macosx_free_contents (GdkDisplay *display, + GdkToplevelMacOSX *toplevel) +{ + if (toplevel->icon_window) + { + g_object_unref (toplevel->icon_window); + toplevel->icon_window = NULL; + } + if (toplevel->icon_pixmap) + { + g_object_unref (toplevel->icon_pixmap); + toplevel->icon_pixmap = NULL; + } + if (toplevel->icon_mask) + { + g_object_unref (toplevel->icon_mask); + toplevel->icon_mask = NULL; + } + if (toplevel->group_leader) + { + g_object_unref (toplevel->group_leader); + toplevel->group_leader = NULL; + } +#ifdef HAVE_XSYNC + if (toplevel->update_counter != None) + { + XSyncDestroyCounter (GDK_DISPLAY_XDISPLAY (display), + toplevel->update_counter); + toplevel->update_counter = None; + + XSyncIntToValue (&toplevel->current_counter_value, 0); + } +#endif +} + +void +_gdk_windowing_window_destroy (GdkWindow *window, + gboolean recursing, + gboolean foreign_destroy) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkToplevelMacOSX *toplevel; + GdkDrawableImplMacOSX *draw_impl; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + _gdk_selection_window_destroyed (window); + + if (private->extension_events != 0) + _gdk_input_window_destroy (window); + + toplevel = _gdk_macosx_window_get_toplevel (window); + if (toplevel) + gdk_toplevel_macosx_free_contents (GDK_WINDOW_DISPLAY (window), toplevel); + + draw_impl = GDK_DRAWABLE_IMPL_MACOSX (private->impl); + + if (draw_impl->xft_draw) + XftDrawDestroy (draw_impl->xft_draw); + + if (!recursing && !foreign_destroy) + { + XDestroyWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window)); + } +} + +void +_gdk_windowing_window_destroy_foreign (GdkWindow *window) +{ + /* It's somebody else's window, but in our heirarchy, + * so reparent it to the root window, and then send + * it a delete event, as if we were a WM + */ + XClientMessageEvent xevent; + + gdk_error_trap_push (); + gdk_window_hide (window); + gdk_window_reparent (window, NULL, 0, 0); + + xevent.type = ClientMessage; + xevent.window = GDK_WINDOW_XID (window); + xevent.message_type = gdk_macosx_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), + "WM_PROTOCOLS"); + xevent.format = 32; + xevent.data.l[0] = gdk_macosx_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), + "WM_DELETE_WINDOW"); + xevent.data.l[1] = CurrentTime; + xevent.data.l[2] = 0; + xevent.data.l[3] = 0; + xevent.data.l[4] = 0; + + XSendEvent (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + False, 0, (XEvent *)&xevent); + gdk_display_sync (GDK_WINDOW_DISPLAY (window)); + gdk_error_trap_pop (); +} + +static GdkWindow * +get_root (GdkWindow *window) +{ + GdkScreen *screen = gdk_drawable_get_screen (window); + + return gdk_screen_get_root_window (screen); +} + +/* This function is called when the XWindow is really gone. + */ +void +gdk_window_destroy_notify (GdkWindow *window) +{ + GdkWindowImplMacOSX *window_impl; + + g_return_if_fail (window != NULL); + + window_impl = GDK_WINDOW_IMPL_MACOSX (((GdkWindowObject *)window)->impl); + + if (!GDK_WINDOW_DESTROYED (window)) + { + if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_FOREIGN) + g_warning ("GdkWindow %#lx unexpectedly destroyed", GDK_WINDOW_XID (window)); + + _gdk_window_destroy (window, TRUE); + } + + _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), GDK_WINDOW_XID (window)); + if (window_impl->toplevel && window_impl->toplevel->focus_window) + _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), window_impl->toplevel->focus_window); + + _gdk_xgrab_check_destroy (window); + + g_object_unref (window); +} + +static void +update_wm_hints (GdkWindow *window, + gboolean force) +{ + GdkToplevelMacOSX *toplevel = _gdk_macosx_window_get_toplevel (window); + GdkWindowObject *private = (GdkWindowObject *)window; + GdkDisplay *display = GDK_WINDOW_DISPLAY (window); + XWMHints wm_hints; + + if (!force && + !toplevel->is_leader && + private->state & GDK_WINDOW_STATE_WITHDRAWN) + return; + + wm_hints.flags = StateHint | InputHint; + wm_hints.input = private->accept_focus ? True : False; + wm_hints.initial_state = NormalState; + + if (private->state & GDK_WINDOW_STATE_ICONIFIED) + { + wm_hints.flags |= StateHint; + wm_hints.initial_state = IconicState; + } + + if (toplevel->icon_window && !GDK_WINDOW_DESTROYED (toplevel->icon_window)) + { + wm_hints.flags |= IconWindowHint; + wm_hints.icon_window = GDK_WINDOW_XID (toplevel->icon_window); + } + + if (toplevel->icon_pixmap) + { + wm_hints.flags |= IconPixmapHint; + wm_hints.icon_pixmap = GDK_PIXMAP_XID (toplevel->icon_pixmap); + } + + if (toplevel->icon_mask) + { + wm_hints.flags |= IconMaskHint; + wm_hints.icon_mask = GDK_PIXMAP_XID (toplevel->icon_mask); + } + + wm_hints.flags |= WindowGroupHint; + if (toplevel->group_leader && !GDK_WINDOW_DESTROYED (toplevel->group_leader)) + { + wm_hints.flags |= WindowGroupHint; + wm_hints.window_group = GDK_WINDOW_XID (toplevel->group_leader); + } + else + wm_hints.window_group = GDK_DISPLAY_MACOSX (display)->leader_window; + + XSetWMHints (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + &wm_hints); +} + +static void +set_initial_hints (GdkWindow *window) +{ + GdkDisplay *display = GDK_WINDOW_DISPLAY (window); + Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); + Window xwindow = GDK_WINDOW_XID (window); + GdkWindowObject *private; + GdkToplevelMacOSX *toplevel; + Atom atoms[7]; + gint i; + + private = (GdkWindowObject*) window; + toplevel = _gdk_macosx_window_get_toplevel (window); + + if (!toplevel) + return; + + update_wm_hints (window, TRUE); + + /* We set the spec hints regardless of whether the spec is supported, + * since it can't hurt and it's kind of expensive to check whether + * it's supported. + */ + + i = 0; + + if (private->state & GDK_WINDOW_STATE_MAXIMIZED) + { + atoms[i] = gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_WM_STATE_MAXIMIZED_VERT"); + ++i; + atoms[i] = gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_WM_STATE_MAXIMIZED_HORZ"); + ++i; + } + + if (private->state & GDK_WINDOW_STATE_ABOVE) + { + atoms[i] = gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_WM_STATE_ABOVE"); + ++i; + } + + if (private->state & GDK_WINDOW_STATE_BELOW) + { + atoms[i] = gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_WM_STATE_BELOW"); + ++i; + } + + if (private->state & GDK_WINDOW_STATE_STICKY) + { + atoms[i] = gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_WM_STATE_STICKY"); + ++i; + } + + if (private->state & GDK_WINDOW_STATE_FULLSCREEN) + { + atoms[i] = gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_WM_STATE_FULLSCREEN"); + ++i; + } + + if (private->modal_hint) + { + atoms[i] = gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_WM_STATE_MODAL"); + ++i; + } + + if (toplevel->skip_taskbar_hint) + { + atoms[i] = gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_WM_STATE_SKIP_TASKBAR"); + ++i; + } + + if (toplevel->skip_pager_hint) + { + atoms[i] = gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_WM_STATE_SKIP_PAGER"); + ++i; + } + + if (i > 0) + { + XChangeProperty (xdisplay, + xwindow, + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_STATE"), + XA_ATOM, 32, PropModeReplace, + (guchar*) atoms, i); + } + else + { + XDeleteProperty (xdisplay, + xwindow, + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_STATE")); + } + + if (private->state & GDK_WINDOW_STATE_STICKY) + { + atoms[0] = 0xFFFFFFFF; + XChangeProperty (xdisplay, + xwindow, + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"), + XA_CARDINAL, 32, PropModeReplace, + (guchar*) atoms, 1); + } + else + { + XDeleteProperty (xdisplay, + xwindow, + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP")); + } + + toplevel->map_serial = NextRequest (xdisplay); +} + +static void +show_window_internal (GdkWindow *window, + gboolean raise) +{ + GdkWindowObject *private; + GdkDisplay *display; + GdkDisplayMacOSX *display_macosx; + GdkToplevelMacOSX *toplevel; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject*) window; + if (!private->destroyed) + { + GdkWindowImplMacOSX *impl = GDK_WINDOW_IMPL_MACOSX (private->impl); + Display *xdisplay = GDK_WINDOW_XDISPLAY (window); + Window xwindow = GDK_WINDOW_XID (window); + + if (raise) + XRaiseWindow (xdisplay, xwindow); + + if (!GDK_WINDOW_IS_MAPPED (window)) + { + set_initial_hints (window); + + gdk_synthesize_window_state (window, + GDK_WINDOW_STATE_WITHDRAWN, + 0); + } + + g_assert (GDK_WINDOW_IS_MAPPED (window)); + + if (WINDOW_IS_TOPLEVEL (window)) + { + display = gdk_drawable_get_display (window); + display_macosx = GDK_DISPLAY_MACOSX (display); + toplevel = _gdk_macosx_window_get_toplevel (window); + + if (toplevel->user_time != 0 && + display_macosx->user_time != 0 && + XSERVER_TIME_IS_LATER (display_macosx->user_time, toplevel->user_time)) + gdk_macosx_window_set_user_time (window, display_macosx->user_time); + } + + if (impl->position_info.mapped) + { + gboolean unset_bg = !private->input_only && + (private->window_type == GDK_WINDOW_CHILD || + impl->override_redirect) && + gdk_window_is_viewable (window); + + if (unset_bg) + _gdk_macosx_window_tmp_unset_bg (window, TRUE); + + XMapWindow (xdisplay, xwindow); + + if (unset_bg) + { + _gdk_macosx_window_tmp_reset_bg (window, TRUE); + gdk_window_invalidate_rect (window, NULL, TRUE); + } + } + } +} + +/** + * gdk_window_show_unraised: + * @window: a #GdkWindow + * + * Shows a #GdkWindow onscreen, but does not modify its stacking + * order. In contrast, gdk_window_show() will raise the window + * to the top of the window stack. + * + * On the MACOSX platform, in Xlib terms, this function calls + * XMapWindow() (it also updates some internal GDK state, which means + * that you can't really use XMapWindow() directly on a GDK window). + * + **/ +void +gdk_window_show_unraised (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + show_window_internal (window, FALSE); +} + +/** + * gdk_window_show: + * @window: a #GdkWindow + * + * Like gdk_window_show_unraised(), but also raises the window to the + * top of the window stack (moves the window to the front of the + * Z-order). + * + * This function maps a window so it's visible onscreen. Its opposite + * is gdk_window_hide(). + * + * When implementing a #GtkWidget, you should call this function on the widget's + * #GdkWindow as part of the "map" method. + * + **/ +void +gdk_window_show (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + show_window_internal (window, TRUE); +} + +static void +pre_unmap (GdkWindow *window) +{ + GdkWindow *start_window = NULL; + GdkWindowObject *private = (GdkWindowObject *)window; + + if (private->input_only) + return; + + if (private->window_type == GDK_WINDOW_CHILD) + start_window = (GdkWindow *)private->parent; + else if (private->window_type == GDK_WINDOW_TEMP) + start_window = get_root (window); + + if (start_window) + _gdk_macosx_window_tmp_unset_bg (start_window, TRUE); +} + +static void +post_unmap (GdkWindow *window) +{ + GdkWindow *start_window = NULL; + GdkWindowObject *private = (GdkWindowObject *)window; + + if (private->input_only) + return; + + if (private->window_type == GDK_WINDOW_CHILD) + start_window = (GdkWindow *)private->parent; + else if (private->window_type == GDK_WINDOW_TEMP) + start_window = get_root (window); + + if (start_window) + { + _gdk_macosx_window_tmp_reset_bg (start_window, TRUE); + + if (private->window_type == GDK_WINDOW_CHILD && private->parent) + { + GdkRectangle invalid_rect; + + gdk_window_get_position (window, &invalid_rect.x, &invalid_rect.y); + gdk_drawable_get_size (GDK_DRAWABLE (window), + &invalid_rect.width, &invalid_rect.height); + gdk_window_invalidate_rect ((GdkWindow *)private->parent, + &invalid_rect, TRUE); + } + } +} + +/** + * gdk_window_hide: + * @window: a #GdkWindow + * + * For toplevel windows, withdraws them, so they will no longer be + * known to the window manager; for all windows, unmaps them, so + * they won't be displayed. Normally done automatically as + * part of gtk_widget_hide(). + * + **/ +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowObject*) window; + + /* We'll get the unmap notify eventually, and handle it then, + * but checking here makes things more consistent if we are + * just doing stuff ourself. + */ + _gdk_xgrab_check_unmap (window, + NextRequest (GDK_WINDOW_XDISPLAY (window))); + + /* You can't simply unmap toplevel windows. */ + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: /* ? */ + gdk_window_withdraw (window); + return; + break; + + case GDK_WINDOW_FOREIGN: + case GDK_WINDOW_ROOT: + case GDK_WINDOW_CHILD: + break; + } + + if (!private->destroyed) + { + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_WITHDRAWN); + + g_assert (!GDK_WINDOW_IS_MAPPED (window)); + + _gdk_window_clear_update_area (window); + + pre_unmap (window); + + XUnmapWindow (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window)); + + post_unmap (window); + } +} + +/** + * gdk_window_withdraw: + * @window: a toplevel #GdkWindow + * + * Withdraws a window (unmaps it and asks the window manager to forget about it). + * This function is not really useful as gdk_window_hide() automatically + * withdraws toplevel windows before hiding them. + * + **/ +void +gdk_window_withdraw (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowObject*) window; + if (!private->destroyed) + { + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_WITHDRAWN); + + g_assert (!GDK_WINDOW_IS_MAPPED (window)); + + pre_unmap (window); + + XWithdrawWindow (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), 0); + + post_unmap (window); + } +} + +/** + * gdk_window_move: + * @window: a #GdkWindow + * @x: X coordinate relative to window's parent + * @y: Y coordinate relative to window's parent + * + * Repositions a window relative to its parent window. + * For toplevel windows, window managers may ignore or modify the move; + * you should probably use gtk_window_move() on a #GtkWindow widget + * anyway, instead of using GDK functions. For child windows, + * the move will reliably succeed. + * + * If you're also planning to resize the window, use gdk_window_move_resize() + * to both move and resize simultaneously, for a nicer visual effect. + **/ +void +gdk_window_move (GdkWindow *window, + gint x, + gint y) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowImplMacOSX *impl; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + impl = GDK_WINDOW_IMPL_MACOSX (private->impl); + + if (!GDK_WINDOW_DESTROYED (window)) + { + if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD) + { + _gdk_window_move_resize_child (window, x, y, + impl->width, impl->height); + } + else + { + XMoveWindow (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + x, y); + + if (impl->override_redirect) + { + private->x = x; + private->y = y; + } + } + } +} + +/** + * gdk_window_resize: + * @window: a #GdkWindow + * @width: new width of the window + * @height: new height of the window + * + * Resizes @window; for toplevel windows, asks the window manager to resize + * the window. The window manager may not allow the resize. When using GTK+, + * use gtk_window_resize() instead of this low-level GDK function. + * + * Windows may not be resized below 1x1. + * + * If you're also planning to move the window, use gdk_window_move_resize() + * to both move and resize simultaneously, for a nicer visual effect. + **/ +void +gdk_window_resize (GdkWindow *window, + gint width, + gint height) +{ + GdkWindowObject *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowObject*) window; + + if (!GDK_WINDOW_DESTROYED (window)) + { + if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD) + { + _gdk_window_move_resize_child (window, private->x, private->y, + width, height); + } + else + { + GdkWindowImplMacOSX *impl = GDK_WINDOW_IMPL_MACOSX (private->impl); + + XResizeWindow (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + width, height); + + if (impl->override_redirect) + { + impl->width = width; + impl->height = height; + } + else + { + if (width != impl->width || height != impl->height) + private->resize_count += 1; + } + } + } +} + +/** + * gdk_window_move_resize: + * @window: a #GdkWindow + * @x: new X position relative to window's parent + * @y: new Y position relative to window's parent + * @width: new width + * @height: new height + * + * Equivalent to calling gdk_window_move() and gdk_window_resize(), + * except that both operations are performed at once, avoiding strange + * visual effects. (i.e. the user may be able to see the window first + * move, then resize, if you don't use gdk_window_move_resize().) + **/ +void +gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowObject *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowObject*) window; + + if (!GDK_WINDOW_DESTROYED (window)) + { + if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD) + { + _gdk_window_move_resize_child (window, x, y, width, height); + } + else + { + GdkWindowImplMacOSX *impl = GDK_WINDOW_IMPL_MACOSX (private->impl); + + XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + x, y, width, height); + if (impl->override_redirect) + { + private->x = x; + private->y = y; + impl->width = width; + impl->height = height; + } + else + { + if (width != impl->width || height != impl->height) + private->resize_count += 1; + } + } + } +} + +/** + * gdk_window_reparent: + * @window: a #GdkWindow + * @new_parent: new parent to move @window into + * @x: X location inside the new parent + * @y: Y location inside the new parent + * + * Reparents @window into the given @new_parent. The window being + * reparented will be unmapped as a side effect. + * + **/ +void +gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkDisplay *display; + GdkWindowObject *window_private; + GdkWindowObject *parent_private; + GdkWindowObject *old_parent_private; + GdkWindowImplMacOSX *impl; + gboolean was_toplevel; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent)); + g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT); + + if (GDK_WINDOW_DESTROYED (window) || + (new_parent && GDK_WINDOW_DESTROYED (new_parent))) + { + return; + } + + if (!new_parent) + new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window)); + + display = GDK_WINDOW_DISPLAY (window); + + window_private = (GdkWindowObject*) window; + old_parent_private = (GdkWindowObject*)window_private->parent; + parent_private = (GdkWindowObject*) new_parent; + impl = GDK_WINDOW_IMPL_MACOSX (window_private->impl); + + XReparentWindow (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + GDK_WINDOW_XID (new_parent), + x, y); + + window_private->x = x; + window_private->y = y; + + /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like + * the root window + */ + if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN) + new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window)); + + window_private->parent = (GdkWindowObject *)new_parent; + + /* Switch the window type as appropriate */ + + switch (GDK_WINDOW_TYPE (new_parent)) + { + case GDK_WINDOW_ROOT: + case GDK_WINDOW_FOREIGN: + was_toplevel = WINDOW_IS_TOPLEVEL (window); + + if (impl->toplevel_window_type != -1) + GDK_WINDOW_TYPE (window) = impl->toplevel_window_type; + else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD) + GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL; + + if (WINDOW_IS_TOPLEVEL (window) && !was_toplevel) + setup_toplevel_window (window, new_parent); + break; + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + if (WINDOW_IS_TOPLEVEL (window)) + { + /* Save the original window type so we can restore it if the + * window is reparented back to be a toplevel + */ + impl->toplevel_window_type = GDK_WINDOW_TYPE (window); + GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD; + if (impl->toplevel) + { + if (impl->toplevel->focus_window) + { + XDestroyWindow (GDK_WINDOW_XDISPLAY (window), impl->toplevel->focus_window); + _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), impl->toplevel->focus_window); + } + + gdk_toplevel_macosx_free_contents (GDK_WINDOW_DISPLAY (window), + impl->toplevel); + g_free (impl->toplevel); + impl->toplevel = NULL; + } + } + } + + if (old_parent_private) + old_parent_private->children = g_list_remove (old_parent_private->children, window); + + if ((old_parent_private && + (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) || + (!old_parent_private && parent_private->guffaw_gravity)) + gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity); + + parent_private->children = g_list_prepend (parent_private->children, window); + _gdk_window_init_position (GDK_WINDOW (window_private)); +} +#endif + +void +_gdk_windowing_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_WINDOW_DESTROYED (window)) { + CGRect rect = CGRectMake(x,y,width,height); + CGContextRef context = [GDK_WINDOW_NSVIEW(window) cg]; + CGContextClearRect(context, rect); + } +} + +void +_gdk_windowing_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_WINDOW_DESTROYED (window)) { + CGRect rect = CGRectMake(x,y,width,height); + CGContextRef context = [GDK_WINDOW_NSVIEW(window) cg]; + CGContextClearRect(context, rect); + [GDK_WINDOW_NSVIEW(window) setNeedsDisplayInRect:NSMakeRect(x,y,width,height)]; + } +} + + +#if 0 +/** + * gdk_window_raise: + * @window: a #GdkWindow + * + * Raises @window to the top of the Z-order (stacking order), so that + * other windows with the same parent window appear below @window. + * This is true whether or not the windows are visible. + * + * If @window is a toplevel, the window manager may choose to deny the + * request to move the window in the Z-order, gdk_window_raise() only + * requests the restack, does not guarantee it. + * + **/ +void +gdk_window_raise (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_WINDOW_DESTROYED (window)) + XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window)); +} + +/** + * gdk_window_lower: + * @window: a #GdkWindow + * + * Lowers @window to the bottom of the Z-order (stacking order), so that + * other windows with the same parent window appear above @window. + * This is true whether or not the other windows are visible. + * + * If @window is a toplevel, the window manager may choose to deny the + * request to move the window in the Z-order, gdk_window_lower() only + * requests the restack, does not guarantee it. + * + * Note that gdk_window_show() raises the window again, so don't call this + * function before gdk_window_show(). (Try gdk_window_show_unraised().) + * + **/ +void +gdk_window_lower (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_WINDOW_DESTROYED (window)) + XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window)); +} + +/** + * gdk_window_focus: + * @window: a #GdkWindow + * @timestamp: timestamp of the event triggering the window focus + * + * Sets keyboard focus to @window. If @window is not onscreen this + * will not work. In most cases, gtk_window_present() should be used on + * a #GtkWindow, rather than calling this function. + * + **/ +void +gdk_window_focus (GdkWindow *window, + guint32 timestamp) +{ + GdkDisplay *display; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + display = GDK_WINDOW_DISPLAY (window); + + if (gdk_macosx_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window), + gdk_atom_intern ("_NET_ACTIVE_WINDOW", FALSE))) + { + XEvent xev; + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = GDK_WINDOW_XWINDOW (window); + xev.xclient.message_type = gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_ACTIVE_WINDOW"); + xev.xclient.format = 32; + xev.xclient.data.l[0] = 1; /* requestor type; we're an app */ + xev.xclient.data.l[1] = timestamp; + xev.xclient.data.l[2] = None; /* currently active window */ + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); + } + else + { + XRaiseWindow (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window)); + + /* There is no way of knowing reliably whether we are viewable; + * _gdk_macosx_set_input_focus_safe() traps errors asynchronously. + */ + _gdk_macosx_set_input_focus_safe (display, GDK_WINDOW_XID (window), + RevertToParent, + timestamp); + } +} + +/** + * gdk_window_set_hints: + * @window: a #GdkWindow + * @x: ignored field, does not matter + * @y: ignored field, does not matter + * @min_width: minimum width hint + * @min_height: minimum height hint + * @max_width: max width hint + * @max_height: max height hint + * @flags: logical OR of GDK_HINT_POS, GDK_HINT_MIN_SIZE, and/or GDK_HINT_MAX_SIZE + * + * This function is broken and useless and you should ignore it. + * If using GTK+, use functions such as gtk_window_resize(), gtk_window_set_size_request(), + * gtk_window_move(), gtk_window_parse_geometry(), and gtk_window_set_geometry_hints(), + * depending on what you're trying to do. + * + * If using GDK directly, use gdk_window_set_geometry_hints(). + * + **/ +void +gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags) +{ + XSizeHints size_hints; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + size_hints.flags = 0; + + if (flags & GDK_HINT_POS) + { + size_hints.flags |= PPosition; + size_hints.x = x; + size_hints.y = y; + } + + if (flags & GDK_HINT_MIN_SIZE) + { + size_hints.flags |= PMinSize; + size_hints.min_width = min_width; + size_hints.min_height = min_height; + } + + if (flags & GDK_HINT_MAX_SIZE) + { + size_hints.flags |= PMaxSize; + size_hints.max_width = max_width; + size_hints.max_height = max_height; + } + + /* FIXME: Would it be better to delete this property if + * flags == 0? It would save space on the server + */ + XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + &size_hints); +} + +/** + * gdk_window_set_type_hint: + * @window: A toplevel #GdkWindow + * @hint: A hint of the function this window will have + * + * The application can use this call to provide a hint to the window + * manager about the functionality of a window. The window manager + * can use this information when determining the decoration and behaviour + * of the window. + * + * The hint must be set before the window is mapped. + **/ +void +gdk_window_set_type_hint (GdkWindow *window, + GdkWindowTypeHint hint) +{ + GdkDisplay *display; + Atom atom; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + display = gdk_drawable_get_display (window); + + switch (hint) + { + case GDK_WINDOW_TYPE_HINT_DIALOG: + atom = gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG"); + break; + case GDK_WINDOW_TYPE_HINT_MENU: + atom = gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU"); + break; + case GDK_WINDOW_TYPE_HINT_TOOLBAR: + atom = gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR"); + break; + case GDK_WINDOW_TYPE_HINT_UTILITY: + atom = gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY"); + break; + case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN: + atom = gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASH"); + break; + case GDK_WINDOW_TYPE_HINT_DOCK: + atom = gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK"); + break; + case GDK_WINDOW_TYPE_HINT_DESKTOP: + atom = gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP"); + break; + default: + g_warning ("Unknown hint %d passed to gdk_window_set_type_hint", hint); + /* Fall thru */ + case GDK_WINDOW_TYPE_HINT_NORMAL: + atom = gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NORMAL"); + break; + } + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"), + XA_ATOM, 32, PropModeReplace, + (guchar *)&atom, 1); +} + + +static void +gdk_wmspec_change_state (gboolean add, + GdkWindow *window, + GdkAtom state1, + GdkAtom state2) +{ + GdkDisplay *display = GDK_WINDOW_DISPLAY (window); + XEvent xev; + +#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ +#define _NET_WM_STATE_ADD 1 /* add/set property */ +#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = GDK_WINDOW_XID (window); + xev.xclient.message_type = gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_STATE"); + xev.xclient.format = 32; + xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + xev.xclient.data.l[1] = gdk_macosx_atom_to_xatom_for_display (display, state1); + xev.xclient.data.l[2] = gdk_macosx_atom_to_xatom_for_display (display, state2); + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +/** + * gdk_window_set_modal_hint: + * @window: A toplevel #GdkWindow + * @modal: TRUE if the window is modal, FALSE otherwise. + * + * The application can use this hint to tell the window manager + * that a certain window has modal behaviour. The window manager + * can use this information to handle modal windows in a special + * way. + * + * You should only use this on windows for which you have + * previously called #gdk_window_set_transient_for() + **/ +void +gdk_window_set_modal_hint (GdkWindow *window, + gboolean modal) +{ + GdkWindowObject *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + private = (GdkWindowObject*) window; + + private->modal_hint = modal; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (modal, window, + gdk_atom_intern ("_NET_WM_STATE_MODAL", FALSE), + NULL); +} + +/** + * gdk_window_set_skip_taskbar_hint: + * @window: a toplevel #GdkWindow + * @skips_taskbar: %TRUE to skip the taskbar + * + * Toggles whether a window should appear in a task list or window + * list. If a window's semantic type as specified with + * gdk_window_set_type_hint() already fully describes the window, this + * function should NOT be called in addition, instead you should allow + * the window to be treated according to standard policy for its + * semantic type. + * + * Since: 2.2 + **/ +void +gdk_window_set_skip_taskbar_hint (GdkWindow *window, + gboolean skips_taskbar) +{ + GdkToplevelMacOSX *toplevel; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + toplevel = _gdk_macosx_window_get_toplevel (window); + toplevel->skip_taskbar_hint = skips_taskbar; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (skips_taskbar, window, + gdk_atom_intern ("_NET_WM_STATE_SKIP_TASKBAR", FALSE), + NULL); +} + +/** + * gdk_window_set_skip_pager_hint: + * @window: a toplevel #GdkWindow + * @skips_pager: %TRUE to skip the pager + * + * Toggles whether a window should appear in a pager (workspace + * switcher, or other desktop utility program that displays a small + * thumbnail representation of the windows on the desktop). If a + * window's semantic type as specified with gdk_window_set_type_hint() + * already fully describes the window, this function should NOT be + * called in addition, instead you should allow the window to be + * treated according to standard policy for its semantic type. + * + * Since: 2.2 + **/ +void +gdk_window_set_skip_pager_hint (GdkWindow *window, + gboolean skips_pager) +{ + GdkToplevelMacOSX *toplevel; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + toplevel = _gdk_macosx_window_get_toplevel (window); + toplevel->skip_pager_hint = skips_pager; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (skips_pager, window, + gdk_atom_intern ("_NET_WM_STATE_SKIP_PAGER", FALSE), + NULL); +} + +/** + * gdk_window_set_geometry_hints: + * @window: a toplevel #GdkWindow + * @geometry: geometry hints + * @geom_mask: bitmask indicating fields of @geometry to pay attention to + * + * Sets the geometry hints for @window. Hints flagged in @geom_mask + * are set, hints not flagged in @geom_mask are unset. + * To unset all hints, use a @geom_mask of 0 and a @geometry of %NULL. + * + * This function provides hints to the windowing system about + * acceptable sizes for a toplevel window. The purpose of + * this is to constrain user resizing, but the windowing system + * will typically (but is not required to) also constrain the + * current size of the window to the provided values and + * constrain programatic resizing via gdk_window_resize() or + * gdk_window_move_resize(). + * + * Note that on X11, this effect has no effect on windows + * of type GDK_WINDOW_TEMP or windows where override_redirect + * has been turned on via gdk_window_set_override_redirect() + * since these windows are not resizable by the user. + * + * Since you can't count on the windowing system doing the + * constraints for programmatic resizes, you should generally + * call gdk_window_constrain_size() yourself to determine + * appropriate sizes. + * + **/ +void +gdk_window_set_geometry_hints (GdkWindow *window, + GdkGeometry *geometry, + GdkWindowHints geom_mask) +{ + XSizeHints size_hints; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + size_hints.flags = 0; + + if (geom_mask & GDK_HINT_POS) + { + size_hints.flags |= PPosition; + /* We need to initialize the following obsolete fields because KWM + * apparently uses these fields if they are non-zero. + * #@#!#!$!. + */ + size_hints.x = 0; + size_hints.y = 0; + } + + if (geom_mask & GDK_HINT_USER_POS) + { + size_hints.flags |= USPosition; + } + + if (geom_mask & GDK_HINT_USER_SIZE) + { + size_hints.flags |= USSize; + } + + if (geom_mask & GDK_HINT_MIN_SIZE) + { + size_hints.flags |= PMinSize; + size_hints.min_width = geometry->min_width; + size_hints.min_height = geometry->min_height; + } + + if (geom_mask & GDK_HINT_MAX_SIZE) + { + size_hints.flags |= PMaxSize; + size_hints.max_width = MAX (geometry->max_width, 1); + size_hints.max_height = MAX (geometry->max_height, 1); + } + + if (geom_mask & GDK_HINT_BASE_SIZE) + { + size_hints.flags |= PBaseSize; + size_hints.base_width = geometry->base_width; + size_hints.base_height = geometry->base_height; + } + + if (geom_mask & GDK_HINT_RESIZE_INC) + { + size_hints.flags |= PResizeInc; + size_hints.width_inc = geometry->width_inc; + size_hints.height_inc = geometry->height_inc; + } + + if (geom_mask & GDK_HINT_ASPECT) + { + size_hints.flags |= PAspect; + if (geometry->min_aspect <= 1) + { + size_hints.min_aspect.x = 65536 * geometry->min_aspect; + size_hints.min_aspect.y = 65536; + } + else + { + size_hints.min_aspect.x = 65536; + size_hints.min_aspect.y = 65536 / geometry->min_aspect;; + } + if (geometry->max_aspect <= 1) + { + size_hints.max_aspect.x = 65536 * geometry->max_aspect; + size_hints.max_aspect.y = 65536; + } + else + { + size_hints.max_aspect.x = 65536; + size_hints.max_aspect.y = 65536 / geometry->max_aspect;; + } + } + + if (geom_mask & GDK_HINT_WIN_GRAVITY) + { + size_hints.flags |= PWinGravity; + size_hints.win_gravity = geometry->win_gravity; + } + + /* FIXME: Would it be better to delete this property if + * geom_mask == 0? It would save space on the server + */ + XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + &size_hints); +} + +static void +gdk_window_get_geometry_hints (GdkWindow *window, + GdkGeometry *geometry, + GdkWindowHints *geom_mask) +{ + XSizeHints size_hints; + glong junk_size_mask = 0; + + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (geometry != NULL); + g_return_if_fail (geom_mask != NULL); + + *geom_mask = 0; + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (!XGetWMNormalHints (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + &size_hints, + &junk_size_mask)) + return; + + if (size_hints.flags & PMinSize) + { + *geom_mask |= GDK_HINT_MIN_SIZE; + geometry->min_width = size_hints.min_width; + geometry->min_height = size_hints.min_height; + } + + if (size_hints.flags & PMaxSize) + { + *geom_mask |= GDK_HINT_MAX_SIZE; + geometry->max_width = MAX (size_hints.max_width, 1); + geometry->max_height = MAX (size_hints.max_height, 1); + } + + if (size_hints.flags & PResizeInc) + { + *geom_mask |= GDK_HINT_RESIZE_INC; + geometry->width_inc = size_hints.width_inc; + geometry->height_inc = size_hints.height_inc; + } + + if (size_hints.flags & PAspect) + { + *geom_mask |= GDK_HINT_ASPECT; + + geometry->min_aspect = (gdouble) size_hints.min_aspect.x / (gdouble) size_hints.min_aspect.y; + geometry->max_aspect = (gdouble) size_hints.max_aspect.x / (gdouble) size_hints.max_aspect.y; + } + + if (size_hints.flags & PWinGravity) + { + *geom_mask |= GDK_HINT_WIN_GRAVITY; + geometry->win_gravity = size_hints.win_gravity; + } +} + +static gboolean +utf8_is_latin1 (const gchar *str) +{ + const char *p = str; + + while (*p) + { + gunichar ch = g_utf8_get_char (p); + + if (ch > 0xff) + return FALSE; + + p = g_utf8_next_char (p); + } + + return TRUE; +} + +/* Set the property to @utf8_str as STRING if the @utf8_str is fully + * convertable to STRING, otherwise, set it as compound text + */ +static void +set_text_property (GdkDisplay *display, + Window xwindow, + Atom property, + const gchar *utf8_str) +{ + guchar *prop_text = NULL; + Atom prop_type; + gint prop_length; + gint prop_format; + gboolean is_compound_text; + + if (utf8_is_latin1 (utf8_str)) + { + prop_type = XA_STRING; + prop_text = gdk_utf8_to_string_target (utf8_str); + prop_length = prop_text ? strlen (prop_text) : 0; + prop_format = 8; + is_compound_text = FALSE; + } + else + { + GdkAtom gdk_type; + + gdk_utf8_to_compound_text_for_display (display, + utf8_str, &gdk_type, &prop_format, + &prop_text, &prop_length); + prop_type = gdk_macosx_atom_to_xatom_for_display (display, gdk_type); + is_compound_text = TRUE; + } + + if (prop_text) + { + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + xwindow, + property, + prop_type, prop_format, + PropModeReplace, prop_text, + prop_length); + + if (is_compound_text) + gdk_free_compound_text (prop_text); + else + g_free (prop_text); + } +} + +/* Set WM_NAME and _NET_WM_NAME + */ +static void +set_wm_name (GdkDisplay *display, + Window xwindow, + const gchar *name) +{ + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow, + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_NAME"), + gdk_macosx_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8, + PropModeReplace, name, strlen (name)); + + set_text_property (display, xwindow, + gdk_macosx_get_xatom_by_name_for_display (display, "WM_NAME"), + name); +} + +/** + * gdk_window_set_title: + * @window: a toplevel #GdkWindow + * @title: title of @window + * + * Sets the title of a toplevel window, to be displayed in the titlebar. + * If you haven't explicitly set the icon name for the window + * (using gdk_window_set_icon_name()), the icon name will be set to + * @title as well. @title must be in UTF-8 encoding (as with all + * user-readable strings in GDK/GTK+). @title may not be %NULL. + **/ +void +gdk_window_set_title (GdkWindow *window, + const gchar *title) +{ + GdkDisplay *display; + Display *xdisplay; + Window xwindow; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (title != NULL); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + display = gdk_drawable_get_display (window); + xdisplay = GDK_DISPLAY_XDISPLAY (display); + xwindow = GDK_WINDOW_XID (window); + + set_wm_name (display, xwindow, title); + + if (!gdk_window_icon_name_set (window)) + { + XChangeProperty (xdisplay, xwindow, + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"), + gdk_macosx_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8, + PropModeReplace, title, strlen (title)); + + set_text_property (display, xwindow, + gdk_macosx_get_xatom_by_name_for_display (display, "WM_ICON_NAME"), + title); + } +} + +/** + * gdk_window_set_role: + * @window: a toplevel #GdkWindow + * @role: a string indicating its role + * + * When using GTK+, typically you should use gtk_window_set_role() instead + * of this low-level function. + * + * The window manager and session manager use a window's role to + * distinguish it from other kinds of window in the same application. + * When an application is restarted after being saved in a previous + * session, all windows with the same title and role are treated as + * interchangeable. So if you have two windows with the same title + * that should be distinguished for session management purposes, you + * should set the role on those windows. It doesn't matter what string + * you use for the role, as long as you have a different role for each + * non-interchangeable kind of window. + * + **/ +void +gdk_window_set_role (GdkWindow *window, + const gchar *role) +{ + GdkDisplay *display; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + display = gdk_drawable_get_display (window); + + if (!GDK_WINDOW_DESTROYED (window)) + { + if (role) + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), + gdk_macosx_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"), + XA_STRING, 8, PropModeReplace, role, strlen (role)); + else + XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), + gdk_macosx_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE")); + } +} + +/** + * gdk_window_set_transient_for: + * @window: a toplevel #GdkWindow + * @parent: another toplevel #GdkWindow + * + * Indicates to the window manager that @window is a transient dialog + * associated with the application window @parent. This allows the + * window manager to do things like center @window on @parent and + * keep @window above @parent. + * + * See gtk_window_set_transient_for() if you're using #GtkWindow or + * #GtkDialog. + * + **/ +void +gdk_window_set_transient_for (GdkWindow *window, + GdkWindow *parent) +{ + GdkWindowObject *private; + GdkWindowObject *parent_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject*) window; + parent_private = (GdkWindowObject*) parent; + + if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent)) + XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + GDK_WINDOW_XID (parent)); +} + +/** + * gdk_window_set_background: + * @window: a #GdkWindow + * @color: an allocated #GdkColor + * + * Sets the background color of @window. (However, when using GTK+, + * set the background of a widget with gtk_widget_modify_bg() - if + * you're an application - or gtk_style_set_background() - if you're + * implementing a custom widget.) + * + * The @color must be allocated; gdk_rgb_find_color() is the best way + * to allocate a color. + * + * See also gdk_window_set_back_pixmap(). + * + **/ +void +gdk_window_set_background (GdkWindow *window, + const GdkColor *color) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_WINDOW_DESTROYED (window)) + XSetWindowBackground (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), color->pixel); + + private->bg_color = *color; + + if (private->bg_pixmap && + private->bg_pixmap != GDK_PARENT_RELATIVE_BG && + private->bg_pixmap != GDK_NO_BG) + g_object_unref (private->bg_pixmap); + + private->bg_pixmap = NULL; +} + +/** + * gdk_window_set_back_pixmap: + * @window: a #GdkWindow + * @pixmap: a #GdkPixmap, or %NULL + * @parent_relative: whether the tiling origin is at the origin of @window's parent + * + * Sets the background pixmap of @window. May also be used to set a background of + * "None" on @window, by setting a background pixmap of %NULL. + * A background pixmap will be tiled, positioning the first tile at the origin of + * @window, or if @parent_relative is %TRUE, the tiling will be done based on the + * origin of the parent window (useful to align tiles in a parent with tiles + * in a child). + * + * A background pixmap of %NULL means that the window will have no + * background. A window with no background will never have its + * background filled by the windowing system, instead the window will + * contain whatever pixels were already in the corresponding area of + * the display. + * + * The windowing system will normally fill a window with its background + * when the window is obscured then exposed, and when you call + * gdk_window_clear(). + * + **/ +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gboolean parent_relative) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + Pixmap xpixmap; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (pixmap == NULL || !parent_relative); + g_return_if_fail (pixmap == NULL || gdk_drawable_get_depth (window) == gdk_drawable_get_depth (pixmap)); + + if (private->bg_pixmap && + private->bg_pixmap != GDK_PARENT_RELATIVE_BG && + private->bg_pixmap != GDK_NO_BG) + g_object_unref (private->bg_pixmap); + + if (parent_relative) + { + xpixmap = ParentRelative; + private->bg_pixmap = GDK_PARENT_RELATIVE_BG; + } + else + { + if (pixmap) + { + g_object_ref (pixmap); + private->bg_pixmap = pixmap; + xpixmap = GDK_PIXMAP_XID (pixmap); + } + else + { + xpixmap = None; + private->bg_pixmap = GDK_NO_BG; + } + } + + if (!GDK_WINDOW_DESTROYED (window)) + XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), xpixmap); +} + +/** + * gdk_window_set_cursor: + * @window: a #GdkWindow + * @cursor: a cursor + * + * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new() or + * gdk_cursor_new_from_pixmap() to create the cursor. + * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create + * a cursor with no pixels in it. Passing %NULL for the @cursor argument + * to gdk_window_set_cursor() means that @window will use the cursor of + * its parent window. Most windows should use this default. + * + **/ +void +gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkCursorPrivate *cursor_private; + Cursor xcursor; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + cursor_private = (GdkCursorPrivate*) cursor; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + if (!GDK_WINDOW_DESTROYED (window)) + XDefineCursor (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + xcursor); +} +#endif + +/** + * gdk_window_get_geometry: + * @window: a #GdkWindow + * @x: return location for X coordinate of window (relative to its parent) + * @y: return location for Y coordinate of window (relative to its parent) + * @width: return location for width of window + * @height: return location for height of window + * @depth: return location for bit depth of window + * + * Any of the return location arguments to this function may be %NULL, + * if you aren't interested in getting the value of that field. + * + * The X and Y coordinates returned are relative to the parent window + * of @window, which for toplevels usually means relative to the + * window decorations (titlebar, etc.) rather than relative to the + * root window (screen-size background window). + * + * On the X11 platform, the geometry is obtained from the X server, + * so reflects the latest position of @window; this may be out-of-sync + * with the position of @window delivered in the most-recently-processed + * #GdkEventConfigure. gdk_window_get_position() in contrast gets the + * position from the most recent configure event. + * + * <note> + * If @window is not a toplevel, it is <emphasis>much</emphasis> better + * to call gdk_window_get_position() and gdk_drawable_get_size() instead, + * because it avoids the roundtrip to the X server and because + * gdk_drawable_get_size() supports the full 32-bit coordinate space, + * whereas gdk_window_get_geometry() is restricted to the 16-bit + * coordinates of X11. + *</note> + **/ +void +gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + g_return_if_fail (window == NULL || GDK_IS_WINDOW (window)); + + if (!window) + { + GDK_NOTE (MULTIHEAD, + g_message ("gdk_window_get_geometry(): Window needs to be non-NULL to be multi head safe")); + window = gdk_screen_get_root_window ((gdk_screen_get_default ())); + } + + if (!GDK_WINDOW_DESTROYED (window)) + { + NSRect frame = [GDK_WINDOW_NSVIEW(window) frame]; + + if (x) + *x = frame.origin.x; + if (y) + *y = frame.origin.y; + if (width) + *width = frame.size.width; + if (height) + *height = frame.size.height; + if (depth) { + NSWindowDepth wdepth = [[GDK_WINDOW_NSVIEW(window) window] depthLimit]; + *depth = NSBitsPerPixelFromDepth(wdepth); + } + } +} + + +/** + * gdk_window_get_origin: + * @window: a #GdkWindow + * @x: return location for X coordinate + * @y: return location for Y coordinate + * + * Obtains the position of a window in root window coordinates. + * (Compare with gdk_window_get_position() and + * gdk_window_get_geometry() which return the position of a window + * relative to its parent window.) + * + * Return value: not meaningful, ignore + **/ +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + NSRect frame; + gint return_val; + gint tx = 0; + gint ty = 0; + + g_return_val_if_fail (window != NULL, 0); + + if (!GDK_WINDOW_DESTROYED (window)) + { + + frame = [GDK_WINDOW_NSVIEW(window) frame]; + + return_val = 1; + } + else + return_val = 0; + + if (x) + *x = frame.origin.x; + if (y) + *y = frame.origin.y; + + return return_val; +} + +#if 0 +/** + * gdk_window_get_deskrelative_origin: + * @window: a toplevel #GdkWindow + * @x: return location for X coordinate + * @y: return location for Y coordinate + * + * This gets the origin of a #GdkWindow relative to + * an Enlightenment-window-manager desktop. As long as you don't + * assume that the user's desktop/workspace covers the entire + * root window (i.e. you don't assume that the desktop begins + * at root window coordinate 0,0) this function is not necessary. + * It's deprecated for that reason. + * + * Return value: not meaningful + **/ +gboolean +gdk_window_get_deskrelative_origin (GdkWindow *window, + gint *x, + gint *y) +{ + gboolean return_val = FALSE; + gint num_children, format_return; + Window win, *child, parent, root; + gint tx = 0; + gint ty = 0; + Atom type_return; + Atom atom; + gulong number_return, bytes_after_return; + guchar *data_return; + + g_return_val_if_fail (window != NULL, FALSE); + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + if (!GDK_WINDOW_DESTROYED (window)) + { + atom = gdk_macosx_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), + "ENLIGHTENMENT_DESKTOP"); + win = GDK_WINDOW_XID (window); + + while (XQueryTree (GDK_WINDOW_XDISPLAY (window), win, &root, &parent, + &child, (unsigned int *)&num_children)) + { + if ((child) && (num_children > 0)) + XFree (child); + + if (!parent) + break; + else + win = parent; + + if (win == root) + break; + + data_return = NULL; + XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), win, atom, 0, 0, + False, XA_CARDINAL, &type_return, &format_return, + &number_return, &bytes_after_return, &data_return); + + if (type_return == XA_CARDINAL) + { + XFree (data_return); + break; + } + } + + return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + win, + 0, 0, &tx, &ty, + &root); + if (x) + *x = tx; + if (y) + *y = ty; + } + + + return return_val; +} + +/** + * gdk_window_get_root_origin: + * @window: a toplevel #GdkWindow + * @x: return location for X position of window frame + * @y: return location for Y position of window frame + * + * Obtains the top-left corner of the window manager frame in root + * window coordinates. + * + **/ +void +gdk_window_get_root_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkRectangle rect; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + gdk_window_get_frame_extents (window, &rect); + + if (x) + *x = rect.x; + + if (y) + *y = rect.y; +} + +/** + * gdk_window_get_frame_extents: + * @window: a toplevel #GdkWindow + * @rect: rectangle to fill with bounding box of the window frame + * + * Obtains the bounding box of the window, including window manager + * titlebar/borders if any. The frame position is given in root window + * coordinates. To get the position of the window itself (rather than + * the frame) in root window coordinates, use gdk_window_get_origin(). + * + **/ +void +gdk_window_get_frame_extents (GdkWindow *window, + GdkRectangle *rect) +{ + GdkDisplay *display; + GdkWindowObject *private; + Window xwindow; + Window xparent; + Window root; + Window *children; + guchar *data; + Window *vroots; + Atom type_return; + guint nchildren; + guint nvroots; + gulong nitems_return; + gulong bytes_after_return; + gint format_return; + gint i; + guint ww, wh, wb, wd; + gint wx, wy; + + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (rect != NULL); + + private = (GdkWindowObject*) window; + + rect->x = 0; + rect->y = 0; + rect->width = 1; + rect->height = 1; + + if (GDK_WINDOW_DESTROYED (window)) + return; + + while (private->parent && ((GdkWindowObject*) private->parent)->parent) + private = (GdkWindowObject*) private->parent; + + /* Refine our fallback answer a bit using local information */ + rect->x = private->x; + rect->y = private->y; + gdk_drawable_get_size ((GdkDrawable *)private, &rect->width, &rect->height); + + if (GDK_WINDOW_DESTROYED (private)) + return; + + gdk_error_trap_push(); + + /* use NETWM_VIRTUAL_ROOTS if available */ + display = gdk_drawable_get_display (window); + root = GDK_WINDOW_XROOTWIN (window); + + nvroots = 0; + vroots = NULL; + + if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), root, + gdk_macosx_get_xatom_by_name_for_display (display, + "_NET_VIRTUAL_ROOTS"), + 0, G_MAXLONG, False, XA_WINDOW, &type_return, + &format_return, &nitems_return, &bytes_after_return, + &data) + == Success) + { + if ((type_return == XA_WINDOW) && (format_return == 32) && (data)) + { + nvroots = nitems_return; + vroots = (Window *)data; + } + } + + xparent = GDK_WINDOW_XID (window); + + do + { + xwindow = xparent; + + if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xwindow, + &root, &xparent, + &children, &nchildren)) + goto fail; + + if (children) + XFree (children); + + /* check virtual roots */ + for (i = 0; i < nvroots; i++) + { + if (xparent == vroots[i]) + { + root = xparent; + break; + } + } + } + while (xparent != root); + + if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow, + &root, &wx, &wy, &ww, &wh, &wb, &wd)) + { + rect->x = wx; + rect->y = wy; + rect->width = ww; + rect->height = wh; + } + + fail: + if (vroots) + XFree (vroots); + + gdk_error_trap_pop (); +} + +#endif + + +void +_gdk_windowing_get_pointer (GdkDisplay *display, + GdkScreen **screen, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindow *return_val = NULL; + NSPoint cursor_loc; + + cursor_loc = [NSEvent mouseLocation]; + + if (x) { + *x = cursor_loc.x; + } + if (y) { + *y = cursor_loc.y; + } + if (screen) { + *screen = gdk_display_get_default_screen (display); + } + if (mask) { + *mask = ns_to_gdk_modifier([[[NSApplication sharedApplication] currentEvent] modifierFlags]); + } +} + + +GdkWindow* +_gdk_windowing_window_get_pointer (GdkDisplay *display, + GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindow *return_val = NULL; + + g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); + + NSPoint cursor_loc; + + cursor_loc = [NSEvent mouseLocation]; + + if (x) { + *x = cursor_loc.x; + } + if (y) { + *y = cursor_loc.y; + } + + *mask = ns_to_gdk_modifier([[[NSApplication sharedApplication] currentEvent] modifierFlags]); + + //FIXME return the GdkWindow it is in + + return return_val; +} + + +GdkWindow* +_gdk_windowing_window_at_pointer (GdkDisplay *display, + gint *win_x, + gint *win_y) +{ + GdkWindow *window = NULL; + GdkScreen *screen; + NSPoint cursor_loc; + + cursor_loc = [NSEvent mouseLocation]; + *win_x = cursor_loc.x; + *win_y = cursor_loc.y; + + //FIXME + + return window; +} + + +#if 0 +/** + * gdk_window_get_events: + * @window: a #GdkWindow + * + * Gets the event mask for @window. See gdk_window_set_events(). + * + * Return value: event mask for @window + **/ +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + XWindowAttributes attrs; + GdkEventMask event_mask; + + g_return_val_if_fail (window != NULL, 0); + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + + if (GDK_WINDOW_DESTROYED (window)) + return 0; + else + { + XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + &attrs); + + event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask); + GDK_WINDOW_OBJECT (window)->event_mask = event_mask; + + return event_mask; + } +} + +/** + * gdk_window_set_events: + * @window: a #GdkWindow + * @event_mask: event mask for @window + * + * The event mask for a window determines which events will be reported + * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK + * means the window should report button press events. The event mask + * is the bitwise OR of values from the #GdkEventMask enumeration. + * + **/ +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + long xevent_mask; + int i; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_WINDOW_DESTROYED (window)) + { + GDK_WINDOW_OBJECT (window)->event_mask = event_mask; + xevent_mask = StructureNotifyMask | PropertyChangeMask; + for (i = 0; i < _gdk_nenvent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= _gdk_event_mask_table[i]; + } + + XSelectInput (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + xevent_mask); + } +} + +static void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + GdkWindow *toplevel; + Window *old_windows; + Window *new_windows; + int i, count; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + toplevel = gdk_window_get_toplevel (window); + + old_windows = NULL; + if (!XGetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel), + GDK_WINDOW_XID (toplevel), + &old_windows, &count)) + { + count = 0; + } + + for (i = 0; i < count; i++) + if (old_windows[i] == GDK_WINDOW_XID (window)) + { + XFree (old_windows); + return; + } + + new_windows = g_new (Window, count + 1); + + for (i = 0; i < count; i++) + new_windows[i] = old_windows[i]; + new_windows[count] = GDK_WINDOW_XID (window); + + XSetWMColormapWindows (GDK_WINDOW_XDISPLAY (toplevel), + GDK_WINDOW_XID (toplevel), + new_windows, count + 1); + + g_free (new_windows); + if (old_windows) + XFree (old_windows); +} + +static gboolean +gdk_window_have_shape_ext (GdkDisplay *display) +{ +#ifdef HAVE_SHAPE_EXT + int ignore; + + return XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (display), + &ignore, &ignore); +#else + return 0; +#endif +} + +#define WARN_SHAPE_TOO_BIG() g_warning ("GdkWindow is too large to allow the use of shape masks or shape regions.") + +/* + * This needs the X11 shape extension. + * If not available, shaped windows will look + * ugly, but programs still work. Stefan Wille + */ +/** + * gdk_window_shape_combine_mask: + * @window: a #GdkWindow + * @mask: shape mask + * @x: X position of shape mask with respect to @window + * @y: Y position of shape mask with respect to @window + * + * Applies a shape mask to @window. Pixels in @window corresponding to + * set bits in the @mask will be visible; pixels in @window + * corresponding to unset bits in the @mask will be transparent. This + * gives a non-rectangular window. + * + * If @mask is %NULL, the shape mask will be unset, and the @x/@y + * parameters are not used. + * + * On the X11 platform, this uses an X server extension which is + * widely available on most common platforms, but not available on + * very old X servers, and occasionally the implementation will be + * buggy. On servers without the shape extension, this function + * will do nothing. + * + * This function works on both toplevel and child windows. + * + **/ +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + Pixmap pixmap; + gint xoffset, yoffset; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + +#ifdef HAVE_SHAPE_EXT + if (GDK_WINDOW_DESTROYED (window)) + return; + + _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset); + + if (xoffset != 0 || yoffset != 0) + { + WARN_SHAPE_TOO_BIG (); + return; + } + + if (gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window))) + { + if (mask) + { + pixmap = GDK_PIXMAP_XID (mask); + } + else + { + x = 0; + y = 0; + pixmap = None; + } + + XShapeCombineMask (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + ShapeBounding, + x, y, + pixmap, + ShapeSet); + } +#endif /* HAVE_SHAPE_EXT */ +} + +/** + * gdk_window_shape_combine_region: + * @window: a #GdkWindow + * @shape_region: region of window to be non-transparent + * @offset_x: X position of @shape_region in @window coordinates + * @offset_y: Y position of @shape_region in @window coordinates + * + * Makes pixels in @window outside @shape_region be transparent, + * so that the window may be nonrectangular. See also + * gdk_window_shape_combine_mask() to use a bitmap as the mask. + * + * If @shape_region is %NULL, the shape will be unset, so the whole + * window will be opaque again. @offset_x and @offset_y are ignored + * if @shape_region is %NULL. + * + * On the X11 platform, this uses an X server extension which is + * widely available on most common platforms, but not available on + * very old X servers, and occasionally the implementation will be + * buggy. On servers without the shape extension, this function + * will do nothing. + * + * This function works on both toplevel and child windows. + * + **/ +void +gdk_window_shape_combine_region (GdkWindow *window, + GdkRegion *shape_region, + gint offset_x, + gint offset_y) +{ + gint xoffset, yoffset; + + g_return_if_fail (GDK_IS_WINDOW (window)); + +#ifdef HAVE_SHAPE_EXT + if (GDK_WINDOW_DESTROYED (window)) + return; + + _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset); + + if (xoffset != 0 || yoffset != 0) + { + WARN_SHAPE_TOO_BIG (); + return; + } + + if (shape_region == NULL) + { + /* Use NULL mask to unset the shape */ + gdk_window_shape_combine_mask (window, NULL, 0, 0); + return; + } + + if (gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window))) + { + gint n_rects = 0; + XRectangle *xrects = NULL; + + _gdk_region_get_xrectangles (shape_region, + 0, 0, + &xrects, &n_rects); + + XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + ShapeBounding, + offset_x, offset_y, + xrects, n_rects, + ShapeSet, + YXBanded); + + g_free (xrects); + } +#endif /* HAVE_SHAPE_EXT */ +} + + +/** + * gdk_window_set_override_redirect: + * @window: a toplevel #GdkWindow + * @override_redirect: %TRUE if window should be override redirect + * + * An override redirect window is not under the control of the window manager. + * This means it won't have a titlebar, won't be minimizable, etc. - it will + * be entirely under the control of the application. The window manager + * can't see the override redirect window at all. + * + * Override redirect should only be used for short-lived temporary + * windows, such as popup menus. #GtkMenu uses an override redirect + * window in its implementation, for example. + * + **/ +void +gdk_window_set_override_redirect (GdkWindow *window, + gboolean override_redirect) +{ + XSetWindowAttributes attr; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_WINDOW_DESTROYED (window)) + { + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowImplMacOSX *impl = GDK_WINDOW_IMPL_MACOSX (private->impl); + + attr.override_redirect = (override_redirect? True : False); + XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + CWOverrideRedirect, + &attr); + + impl->override_redirect = attr.override_redirect; + } +} + +/** + * gdk_window_set_accept_focus: + * @window: a toplevel #GdkWindow + * @accept_focus: %TRUE if the window should receive input focus + * + * Setting @accept_focus to %FALSE hints the desktop environment that the + * window doesn't want to receive input focus. + * + * On X, it is the responsibility of the window manager to interpret this + * hint. ICCCM-compliant window manager usually respect it. + * + * Since: 2.4 + **/ +void +gdk_window_set_accept_focus (GdkWindow *window, + gboolean accept_focus) +{ + GdkWindowObject *private; + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *)window; + + accept_focus = accept_focus != FALSE; + + if (private->accept_focus != accept_focus) + { + private->accept_focus = accept_focus; + + if (!GDK_WINDOW_DESTROYED (window)) + update_wm_hints (window, FALSE); + } +} + +/** + * gdk_window_set_focus_on_map: + * @window: a toplevel #GdkWindow + * @focus_on_map: %TRUE if the window should receive input focus when mapped + * + * Setting @focus_on_map to %FALSE hints the desktop environment that the + * window doesn't want to receive input focus when it is mapped. + * focus_on_map should be turned off for windows that aren't triggered + * interactively (such as popups from network activity). + * + * On X, it is the responsibility of the window manager to interpret + * this hint. Window managers following the freedesktop.org window + * manager extension specification should respect it. + * + * Since: 2.6 + **/ +void +gdk_window_set_focus_on_map (GdkWindow *window, + gboolean focus_on_map) +{ + GdkWindowObject *private; + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowObject *)window; + + focus_on_map = focus_on_map != FALSE; + + if (private->focus_on_map != focus_on_map) + { + private->focus_on_map = focus_on_map; + + if ((!GDK_WINDOW_DESTROYED (window)) && (!private->focus_on_map)) + gdk_macosx_window_set_user_time (window, 0); + } +} + +/** + * gdk_macosx_window_set_user_time: + * @window: A toplevel #GdkWindow + * @timestamp: An XServer timestamp to which the property should be set + * + * The application can use this call to update the _NET_WM_USER_TIME + * property on a toplevel window. This property stores an Xserver + * time which represents the time of the last user input event + * received for this window. This property may be used by the window + * manager to alter the focus, stacking, and/or placement behavior of + * windows when they are mapped depending on whether the new window + * was created by a user action or is a "pop-up" window activated by a + * timer or some other event. + * + * Note that this property is automatically updated by GDK, so this + * function should only be used by applications which handle input + * events bypassing GDK. + * + * Since: 2.6 + **/ +void +gdk_macosx_window_set_user_time (GdkWindow *window, + guint32 timestamp) +{ + GdkDisplay *display; + GdkDisplayMacOSX *display_macosx; + GdkToplevelMacOSX *toplevel; + glong timestamp_long = (glong)timestamp; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + display = gdk_drawable_get_display (window); + display_macosx = GDK_DISPLAY_MACOSX (display); + toplevel = _gdk_macosx_window_get_toplevel (window); + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_USER_TIME"), + XA_CARDINAL, 32, PropModeReplace, + (guchar *)×tamp_long, 1); + + if (timestamp_long != GDK_CURRENT_TIME) + display_macosx->user_time = timestamp_long; + + toplevel->user_time = timestamp_long; +} + +/** + * gdk_window_set_icon_list: + * @window: The #GdkWindow toplevel window to set the icon of. + * @pixbufs: A list of pixbufs, of different sizes. + * + * Sets a list of icons for the window. One of these will be used + * to represent the window when it has been iconified. The icon is + * usually shown in an icon box or some sort of task bar. Which icon + * size is shown depends on the window manager. The window manager + * can scale the icon but setting several size icons can give better + * image quality since the window manager may only need to scale the + * icon by a small amount or not at all. + * + **/ +void +gdk_window_set_icon_list (GdkWindow *window, + GList *pixbufs) +{ + gulong *data; + guchar *pixels; + gulong *p; + gint size; + GList *l; + GdkPixbuf *pixbuf; + gint width, height, stride; + gint x, y; + gint n_channels; + GdkDisplay *display; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + display = gdk_drawable_get_display (window); + + l = pixbufs; + size = 0; + + while (l) + { + pixbuf = l->data; + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + size += 2 + width * height; + + l = g_list_next (l); + } + + data = g_malloc (size * sizeof (gulong)); + + l = pixbufs; + p = data; + while (l) + { + pixbuf = l->data; + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + stride = gdk_pixbuf_get_rowstride (pixbuf); + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + + *p++ = width; + *p++ = height; + + pixels = gdk_pixbuf_get_pixels (pixbuf); + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + guchar r, g, b, a; + + r = pixels[y*stride + x*n_channels + 0]; + g = pixels[y*stride + x*n_channels + 1]; + b = pixels[y*stride + x*n_channels + 2]; + if (n_channels >= 4) + a = pixels[y*stride + x*n_channels + 3]; + else + a = 255; + + *p++ = a << 24 | r << 16 | g << 8 | b ; + } + } + + l = g_list_next (l); + } + + if (size > 0) + { + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_ICON"), + XA_CARDINAL, 32, + PropModeReplace, + (guchar*) data, size); + } + else + { + XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_ICON")); + } + + g_free (data); +} + +/** + * gdk_window_set_icon: + * @window: a toplevel #GdkWindow + * @icon_window: a #GdkWindow to use for the icon, or %NULL to unset + * @pixmap: a #GdkPixmap to use as the icon, or %NULL to unset + * @mask: a 1-bit pixmap (#GdkBitmap) to use as mask for @pixmap, or %NULL to have none + * + * Sets the icon of @window as a pixmap or window. If using GTK+, investigate + * gtk_window_set_default_icon_list() first, and then gtk_window_set_icon_list() + * and gtk_window_set_icon(). If those don't meet your needs, look at + * gdk_window_set_icon_list(). Only if all those are too high-level do you + * want to fall back to gdk_window_set_icon(). + * + **/ +void +gdk_window_set_icon (GdkWindow *window, + GdkWindow *icon_window, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + GdkToplevelMacOSX *toplevel; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + toplevel = _gdk_macosx_window_get_toplevel (window); + + if (toplevel->icon_window != icon_window) + { + if (toplevel->icon_window) + g_object_unref (toplevel->icon_window); + toplevel->icon_window = g_object_ref (icon_window); + } + + if (toplevel->icon_pixmap != pixmap) + { + if (pixmap) + g_object_ref (pixmap); + if (toplevel->icon_pixmap) + g_object_unref (toplevel->icon_pixmap); + toplevel->icon_pixmap = pixmap; + } + + if (toplevel->icon_mask != mask) + { + if (mask) + g_object_ref (mask); + if (toplevel->icon_mask) + g_object_unref (toplevel->icon_mask); + toplevel->icon_mask = mask; + } + + update_wm_hints (window, FALSE); +} + +static gboolean +gdk_window_icon_name_set (GdkWindow *window) +{ + return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window), + g_quark_from_static_string ("gdk-icon-name-set"))); +} + +/** + * gdk_window_set_icon_name: + * @window: a toplevel #GdkWindow + * @name: name of window while iconified (minimized) + * + * Windows may have a name used while minimized, distinct from the + * name they display in their titlebar. Most of the time this is a bad + * idea from a user interface standpoint. But you can set such a name + * with this function, if you like. + * + **/ +void +gdk_window_set_icon_name (GdkWindow *window, + const gchar *name) +{ + GdkDisplay *display; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + display = gdk_drawable_get_display (window); + + g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"), + GUINT_TO_POINTER (TRUE)); + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"), + gdk_macosx_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8, + PropModeReplace, name, strlen (name)); + + set_text_property (display, GDK_WINDOW_XID (window), + gdk_macosx_get_xatom_by_name_for_display (display, "WM_ICON_NAME"), + name); +} + +/** + * gdk_window_iconify: + * @window: a toplevel #GdkWindow + * + * Asks to iconify (minimize) @window. The window manager may choose + * to ignore the request, but normally will honor it. Using + * gtk_window_iconify() is preferred, if you have a #GtkWindow widget. + * + * This function only makes sense when @window is a toplevel window. + * + **/ +void +gdk_window_iconify (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + private = (GdkWindowObject*) window; + + if (GDK_WINDOW_IS_MAPPED (window)) + { + XIconifyWindow (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XWINDOW (window), + gdk_screen_get_number (GDK_WINDOW_SCREEN (window))); + } + else + { + /* Flip our client side flag, the real work happens on map. */ + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_ICONIFIED); + } +} + +/** + * gdk_window_deiconify: + * @window: a toplevel #GdkWindow + * + * Attempt to deiconify (unminimize) @window. On X11 the window manager may + * choose to ignore the request to deiconify. When using GTK+, + * use gtk_window_deiconify() instead of the #GdkWindow variant. Or better yet, + * you probably want to use gtk_window_present(), which raises the window, focuses it, + * unminimizes it, and puts it on the current desktop. + * + **/ +void +gdk_window_deiconify (GdkWindow *window) +{ + GdkWindowObject *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + private = (GdkWindowObject*) window; + + if (GDK_WINDOW_IS_MAPPED (window)) + { + gdk_window_show (window); + } + else + { + /* Flip our client side flag, the real work happens on map. */ + gdk_synthesize_window_state (window, + GDK_WINDOW_STATE_ICONIFIED, + 0); + } +} + +/** + * gdk_window_stick: + * @window: a toplevel #GdkWindow + * + * "Pins" a window such that it's on all workspaces and does not scroll + * with viewports, for window managers that have scrollable viewports. + * (When using #GtkWindow, gtk_window_stick() may be more useful.) + * + * On the X11 platform, this function depends on window manager + * support, so may have no effect with many window managers. However, + * GDK will do the best it can to convince the window manager to stick + * the window. For window managers that don't support this operation, + * there's nothing you can do to force it to happen. + * + **/ +void +gdk_window_stick (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (GDK_WINDOW_IS_MAPPED (window)) + { + /* "stick" means stick to all desktops _and_ do not scroll with the + * viewport. i.e. glue to the monitor glass in all cases. + */ + + XEvent xev; + + /* Request stick during viewport scroll */ + gdk_wmspec_change_state (TRUE, window, + gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE), + NULL); + + /* Request desktop 0xFFFFFFFF */ + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = GDK_WINDOW_XWINDOW (window); + xev.xclient.display = GDK_WINDOW_XDISPLAY (window); + xev.xclient.message_type = gdk_macosx_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), + "_NET_WM_DESKTOP"); + xev.xclient.format = 32; + + xev.xclient.data.l[0] = 0xFFFFFFFF; + xev.xclient.data.l[1] = 0; + xev.xclient.data.l[2] = 0; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); + } + else + { + /* Flip our client side flag, the real work happens on map. */ + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_STICKY); + } +} + +/** + * gdk_window_unstick: + * @window: a toplevel #GdkWindow + * + * Reverse operation for gdk_window_stick(); see gdk_window_stick(), + * and gtk_window_unstick(). + * + **/ +void +gdk_window_unstick (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (GDK_WINDOW_IS_MAPPED (window)) + { + XEvent xev; + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + guchar *data; + gulong *current_desktop; + GdkDisplay *display = gdk_drawable_get_display (window); + + /* Request unstick from viewport */ + gdk_wmspec_change_state (FALSE, window, + gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE), + NULL); + + /* Get current desktop, then set it; this is a race, but not + * one that matters much in practice. + */ + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP"), + 0, G_MAXLONG, + False, XA_CARDINAL, &type, &format, &nitems, + &bytes_after, &data); + + if (type == XA_CARDINAL) + { + current_desktop = (gulong *)data; + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = GDK_WINDOW_XWINDOW (window); + xev.xclient.message_type = gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"); + xev.xclient.format = 32; + + xev.xclient.data.l[0] = *current_desktop; + xev.xclient.data.l[1] = 0; + xev.xclient.data.l[2] = 0; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); + + XFree (current_desktop); + } + } + else + { + /* Flip our client side flag, the real work happens on map. */ + gdk_synthesize_window_state (window, + GDK_WINDOW_STATE_STICKY, + 0); + + } +} + +/** + * gdk_window_maximize: + * @window: a toplevel #GdkWindow + * + * Maximizes the window. If the window was already maximized, then + * this function does nothing. + * + * On X11, asks the window manager to maximize @window, if the window + * manager supports this operation. Not all window managers support + * this, and some deliberately ignore it or don't have a concept of + * "maximized"; so you can't rely on the maximization actually + * happening. But it will happen with most standard window managers, + * and GDK makes a best effort to get it to happen. + * + * On Windows, reliably maximizes the window. + * + **/ +void +gdk_window_maximize (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (TRUE, window, + gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE), + gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE)); + else + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_MAXIMIZED); +} + +/** + * gdk_window_unmaximize: + * @window: a toplevel #GdkWindow + * + * Unmaximizes the window. If the window wasn't maximized, then this + * function does nothing. + * + * On X11, asks the window manager to unmaximize @window, if the + * window manager supports this operation. Not all window managers + * support this, and some deliberately ignore it or don't have a + * concept of "maximized"; so you can't rely on the unmaximization + * actually happening. But it will happen with most standard window + * managers, and GDK makes a best effort to get it to happen. + * + * On Windows, reliably unmaximizes the window. + * + **/ +void +gdk_window_unmaximize (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (FALSE, window, + gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE), + gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE)); + else + gdk_synthesize_window_state (window, + GDK_WINDOW_STATE_MAXIMIZED, + 0); +} + +/** + * gdk_window_fullscreen: + * @window: a toplevel #GdkWindow + * + * Moves the window into fullscreen mode. This means the + * window covers the entire screen and is above any panels + * or task bars. + * + * If the window was already fullscreen, then this function does nothing. + * + * On X11, asks the window manager to put @window in a fullscreen + * state, if the window manager supports this operation. Not all + * window managers support this, and some deliberately ignore it or + * don't have a concept of "fullscreen"; so you can't rely on the + * fullscreenification actually happening. But it will happen with + * most standard window managers, and GDK makes a best effort to get + * it to happen. + * + * Since: 2.2 + **/ +void +gdk_window_fullscreen (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (TRUE, window, + gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN", FALSE), + GDK_NONE); + + else + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_FULLSCREEN); +} + +/** + * gdk_window_unfullscreen: + * @window: a toplevel #GdkWindow + * + * Moves the window out of fullscreen mode. If the window was not + * fullscreen, does nothing. + * + * On X11, asks the window manager to move @window out of the fullscreen + * state, if the window manager supports this operation. Not all + * window managers support this, and some deliberately ignore it or + * don't have a concept of "fullscreen"; so you can't rely on the + * unfullscreenification actually happening. But it will happen with + * most standard window managers, and GDK makes a best effort to get + * it to happen. + * + * Since: 2.2 + **/ +void +gdk_window_unfullscreen (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (FALSE, window, + gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN", FALSE), + GDK_NONE); + + else + gdk_synthesize_window_state (window, + GDK_WINDOW_STATE_FULLSCREEN, + 0); +} + +/** + * gdk_window_set_keep_above: + * @window: a toplevel #GdkWindow + * @setting: whether to keep @window above other windows + * + * Set if @window must be kept above other windows. If the + * window was already above, then this function does nothing. + * + * On X11, asks the window manager to keep @window above, if the window + * manager supports this operation. Not all window managers support + * this, and some deliberately ignore it or don't have a concept of + * "keep above"; so you can't rely on the window being kept above. + * But it will happen with most standard window managers, + * and GDK makes a best effort to get it to happen. + * + * Since: 2.4 + **/ +void +gdk_window_set_keep_above (GdkWindow *window, gboolean setting) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (GDK_WINDOW_IS_MAPPED (window)) + { + if (setting) + gdk_wmspec_change_state (FALSE, window, + gdk_atom_intern ("_NET_WM_STATE_BELOW", FALSE), + GDK_NONE); + gdk_wmspec_change_state (setting, window, + gdk_atom_intern ("_NET_WM_STATE_ABOVE", FALSE), + GDK_NONE); + } + else + gdk_synthesize_window_state (window, + setting ? GDK_WINDOW_STATE_BELOW : GDK_WINDOW_STATE_ABOVE, + setting ? GDK_WINDOW_STATE_ABOVE : 0); +} + +/** + * gdk_window_set_keep_below: + * @window: a toplevel #GdkWindow + * @setting: whether to keep @window below other windows + * + * Set if @window must be kept below other windows. If the + * window was already below, then this function does nothing. + * + * On X11, asks the window manager to keep @window below, if the window + * manager supports this operation. Not all window managers support + * this, and some deliberately ignore it or don't have a concept of + * "keep below"; so you can't rely on the window being kept below. + * But it will happen with most standard window managers, + * and GDK makes a best effort to get it to happen. + * + * Since: 2.4 + **/ +void +gdk_window_set_keep_below (GdkWindow *window, gboolean setting) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (GDK_WINDOW_IS_MAPPED (window)) + { + if (setting) + gdk_wmspec_change_state (FALSE, window, + gdk_atom_intern ("_NET_WM_STATE_ABOVE", FALSE), + GDK_NONE); + gdk_wmspec_change_state (setting, window, + gdk_atom_intern ("_NET_WM_STATE_BELOW", FALSE), + GDK_NONE); + } + else + gdk_synthesize_window_state (window, + setting ? GDK_WINDOW_STATE_ABOVE : GDK_WINDOW_STATE_BELOW, + setting ? GDK_WINDOW_STATE_BELOW : 0); +} + +/** + * gdk_window_get_group: + * @window: a toplevel #GdkWindow + * + * Returns the group leader window for @window. See gdk_window_set_group(). + * + * Return value: the group leader window for @window + * + * Since: 2.4 + **/ +GdkWindow * +gdk_window_get_group (GdkWindow *window) +{ + GdkToplevelMacOSX *toplevel; + + g_return_val_if_fail (window != NULL, NULL); + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + g_return_val_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL); + + if (GDK_WINDOW_DESTROYED (window)) + return NULL; + + toplevel = _gdk_macosx_window_get_toplevel (window); + + return toplevel->group_leader; +} + +/** + * gdk_window_set_group: + * @window: a toplevel #GdkWindow + * @leader: group leader window, or %NULL to restore the default group leader window + * + * Sets the group leader window for @window. By default, + * GDK sets the group leader for all toplevel windows + * to a global window implicitly created by GDK. With this function + * you can override this default. + * + * The group leader window allows the window manager to distinguish + * all windows that belong to a single application. It may for example + * allow users to minimize/unminimize all windows belonging to an + * application at once. You should only set a non-default group window + * if your application pretends to be multiple applications. + **/ +void +gdk_window_set_group (GdkWindow *window, + GdkWindow *leader) +{ + GdkToplevelMacOSX *toplevel; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD); + g_return_if_fail (leader == NULL || GDK_IS_WINDOW (leader)); + + if (GDK_WINDOW_DESTROYED (window) || (leader != NULL && GDK_WINDOW_DESTROYED (leader))) + return; + + toplevel = _gdk_macosx_window_get_toplevel (window); + + if (leader == NULL) + leader = gdk_display_get_default_group (gdk_drawable_get_display (window)); + + if (toplevel->group_leader != leader) + { + if (toplevel->group_leader) + g_object_unref (toplevel->group_leader); + toplevel->group_leader = g_object_ref (leader); + (_gdk_macosx_window_get_toplevel (leader))->is_leader = TRUE; + } + + update_wm_hints (window, FALSE); +} + +static MotifWmHints * +gdk_window_get_mwm_hints (GdkWindow *window) +{ + GdkDisplay *display; + Atom hints_atom = None; + guchar *data; + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + + if (GDK_WINDOW_DESTROYED (window)) + return NULL; + + display = gdk_drawable_get_display (window); + + hints_atom = gdk_macosx_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS); + + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), + hints_atom, 0, sizeof (MotifWmHints)/sizeof (long), + False, AnyPropertyType, &type, &format, &nitems, + &bytes_after, &data); + + if (type == None) + return NULL; + + return (MotifWmHints *)data; +} + +static void +gdk_window_set_mwm_hints (GdkWindow *window, + MotifWmHints *new_hints) +{ + GdkDisplay *display; + Atom hints_atom = None; + guchar *data; + MotifWmHints *hints; + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + + if (GDK_WINDOW_DESTROYED (window)) + return; + + display = gdk_drawable_get_display (window); + + hints_atom = gdk_macosx_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS); + + XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), + hints_atom, 0, sizeof (MotifWmHints)/sizeof (long), + False, AnyPropertyType, &type, &format, &nitems, + &bytes_after, &data); + + if (type == None) + hints = new_hints; + else + { + hints = (MotifWmHints *)data; + + if (new_hints->flags & MWM_HINTS_FUNCTIONS) + { + hints->flags |= MWM_HINTS_FUNCTIONS; + hints->functions = new_hints->functions; + } + if (new_hints->flags & MWM_HINTS_DECORATIONS) + { + hints->flags |= MWM_HINTS_DECORATIONS; + hints->decorations = new_hints->decorations; + } + } + + XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), + hints_atom, hints_atom, 32, PropModeReplace, + (guchar *)hints, sizeof (MotifWmHints)/sizeof (long)); + + if (hints != new_hints) + XFree (hints); +} + +/** + * gdk_window_set_decorations: + * @window: a toplevel #GdkWindow + * @decorations: decoration hint mask + * + * "Decorations" are the features the window manager adds to a toplevel #GdkWindow. + * This function sets the traditional Motif window manager hints that tell the + * window manager which decorations you would like your window to have. + * Usually you should use gtk_window_set_decorated() on a #GtkWindow instead of + * using the GDK function directly. + * + * The @decorations argument is the logical OR of the fields in + * the #GdkWMDecoration enumeration. If #GDK_DECOR_ALL is included in the + * mask, the other bits indicate which decorations should be turned off. + * If #GDK_DECOR_ALL is not included, then the other bits indicate + * which decorations should be turned on. + * + * Most window managers honor a decorations hint of 0 to disable all decorations, + * but very few honor all possible combinations of bits. + * + **/ +void +gdk_window_set_decorations (GdkWindow *window, + GdkWMDecoration decorations) +{ + MotifWmHints hints; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + hints.flags = MWM_HINTS_DECORATIONS; + hints.decorations = decorations; + + gdk_window_set_mwm_hints (window, &hints); +} + +/** + * gdk_window_get_decorations: + * @window: The toplevel #GdkWindow to get the decorations from + * @decorations: The window decorations will be written here + * + * Returns the decorations set on the GdkWindow with #gdk_window_set_decorations + * Returns: TRUE if the window has decorations set, FALSE otherwise. + **/ +gboolean +gdk_window_get_decorations(GdkWindow *window, + GdkWMDecoration *decorations) +{ + MotifWmHints *hints; + gboolean result = FALSE; + + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + hints = gdk_window_get_mwm_hints (window); + + if (hints) + { + if (hints->flags & MWM_HINTS_DECORATIONS) + { + if (decorations) + *decorations = hints->decorations; + result = TRUE; + } + + XFree (hints); + } + + return result; +} + +/** + * gdk_window_set_functions: + * @window: a toplevel #GdkWindow + * @functions: bitmask of operations to allow on @window + * + * This function isn't really good for much. It sets the traditional + * Motif window manager hint for which operations the window manager + * should allow on a toplevel window. However, few window managers do + * anything reliable or interesting with this hint. Many ignore it + * entirely. + * + * The @functions argument is the logical OR of values from the + * #GdkWMFunction enumeration. If the bitmask includes #GDK_FUNC_ALL, + * then the other bits indicate which functions to disable; if + * it doesn't include #GDK_FUNC_ALL, it indicates which functions to + * enable. + * + **/ +void +gdk_window_set_functions (GdkWindow *window, + GdkWMFunction functions) +{ + MotifWmHints hints; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + hints.flags = MWM_HINTS_FUNCTIONS; + hints.functions = functions; + + gdk_window_set_mwm_hints (window, &hints); +} + +#ifdef HAVE_SHAPE_EXT + +/* + * propagate the shapes from all child windows of a GDK window to the parent + * window. Shamelessly ripped from Enlightenment's code + * + * - Raster + */ +struct _gdk_span +{ + gint start; + gint end; + struct _gdk_span *next; +}; + +static void +gdk_add_to_span (struct _gdk_span **s, + gint x, + gint xx) +{ + struct _gdk_span *ptr1, *ptr2, *noo, *ss; + gchar spanning; + + ptr2 = NULL; + ptr1 = *s; + spanning = 0; + ss = NULL; + /* scan the spans for this line */ + while (ptr1) + { + /* -- -> new span */ + /* == -> existing span */ + /* ## -> spans intersect */ + /* if we are in the middle of spanning the span into the line */ + if (spanning) + { + /* case: ---- ==== */ + if (xx < ptr1->start - 1) + { + /* ends before next span - extend to here */ + ss->end = xx; + return; + } + /* case: ----##=== */ + else if (xx <= ptr1->end) + { + /* crosses into next span - delete next span and append */ + ss->end = ptr1->end; + ss->next = ptr1->next; + g_free (ptr1); + return; + } + /* case: ---###--- */ + else + { + /* overlaps next span - delete and keep checking */ + ss->next = ptr1->next; + g_free (ptr1); + ptr1 = ss; + } + } + /* otherwise havent started spanning it in yet */ + else + { + /* case: ---- ==== */ + if (xx < ptr1->start - 1) + { + /* insert span here in list */ + noo = g_malloc (sizeof (struct _gdk_span)); + + if (noo) + { + noo->start = x; + noo->end = xx; + noo->next = ptr1; + if (ptr2) + ptr2->next = noo; + else + *s = noo; + } + return; + } + /* case: ----##=== */ + else if ((x < ptr1->start) && (xx <= ptr1->end)) + { + /* expand this span to the left point of the new one */ + ptr1->start = x; + return; + } + /* case: ===###=== */ + else if ((x >= ptr1->start) && (xx <= ptr1->end)) + { + /* throw the span away */ + return; + } + /* case: ---###--- */ + else if ((x < ptr1->start) && (xx > ptr1->end)) + { + ss = ptr1; + spanning = 1; + ptr1->start = x; + ptr1->end = xx; + } + /* case: ===##---- */ + else if ((x >= ptr1->start) && (x <= ptr1->end + 1) && (xx > ptr1->end)) + { + ss = ptr1; + spanning = 1; + ptr1->end = xx; + } + /* case: ==== ---- */ + /* case handled by next loop iteration - first case */ + } + ptr2 = ptr1; + ptr1 = ptr1->next; + } + /* it started in the middle but spans beyond your current list */ + if (spanning) + { + ptr2->end = xx; + return; + } + /* it does not start inside a span or in the middle, so add it to the end */ + noo = g_malloc (sizeof (struct _gdk_span)); + + if (noo) + { + noo->start = x; + noo->end = xx; + if (ptr2) + { + noo->next = ptr2->next; + ptr2->next = noo; + } + else + { + noo->next = NULL; + *s = noo; + } + } + return; +} + +static void +gdk_add_rectangles (Display *disp, + Window win, + struct _gdk_span **spans, + gint basew, + gint baseh, + gint x, + gint y) +{ + gint a, k; + gint x1, y1, x2, y2; + gint rn, ord; + XRectangle *rl; + + rl = XShapeGetRectangles (disp, win, ShapeBounding, &rn, &ord); + if (rl) + { + /* go through all clip rects in this window's shape */ + for (k = 0; k < rn; k++) + { + /* for each clip rect, add it to each line's spans */ + x1 = x + rl[k].x; + x2 = x + rl[k].x + (rl[k].width - 1); + y1 = y + rl[k].y; + y2 = y + rl[k].y + (rl[k].height - 1); + if (x1 < 0) + x1 = 0; + if (y1 < 0) + y1 = 0; + if (x2 >= basew) + x2 = basew - 1; + if (y2 >= baseh) + y2 = baseh - 1; + for (a = y1; a <= y2; a++) + { + if ((x2 - x1) >= 0) + gdk_add_to_span (&spans[a], x1, x2); + } + } + XFree (rl); + } +} + +static void +gdk_propagate_shapes (Display *disp, + Window win, + gboolean merge) +{ + Window rt, par, *list = NULL; + gint i, j, num = 0, num_rects = 0; + gint x, y, contig; + guint w, h, d; + gint baseh, basew; + XRectangle *rects = NULL; + struct _gdk_span **spans = NULL, *ptr1, *ptr2, *ptr3; + XWindowAttributes xatt; + + XGetGeometry (disp, win, &rt, &x, &y, &w, &h, &d, &d); + if (h <= 0) + return; + basew = w; + baseh = h; + spans = g_malloc (sizeof (struct _gdk_span *) * h); + + for (i = 0; i < h; i++) + spans[i] = NULL; + XQueryTree (disp, win, &rt, &par, &list, (unsigned int *)&num); + if (list) + { + /* go through all child windows and create/insert spans */ + for (i = 0; i < num; i++) + { + if (XGetWindowAttributes (disp, list[i], &xatt) && (xatt.map_state != IsUnmapped)) + if (XGetGeometry (disp, list[i], &rt, &x, &y, &w, &h, &d, &d)) + gdk_add_rectangles (disp, list[i], spans, basew, baseh, x, y); + } + if (merge) + gdk_add_rectangles (disp, win, spans, basew, baseh, x, y); + + /* go through the spans list and build a list of rects */ + rects = g_malloc (sizeof (XRectangle) * 256); + num_rects = 0; + for (i = 0; i < baseh; i++) + { + ptr1 = spans[i]; + /* go through the line for all spans */ + while (ptr1) + { + rects[num_rects].x = ptr1->start; + rects[num_rects].y = i; + rects[num_rects].width = ptr1->end - ptr1->start + 1; + rects[num_rects].height = 1; + j = i + 1; + /* if there are more lines */ + contig = 1; + /* while contigous rects (same start/end coords) exist */ + while ((contig) && (j < baseh)) + { + /* search next line for spans matching this one */ + contig = 0; + ptr2 = spans[j]; + ptr3 = NULL; + while (ptr2) + { + /* if we have an exact span match set contig */ + if ((ptr2->start == ptr1->start) && + (ptr2->end == ptr1->end)) + { + contig = 1; + /* remove the span - not needed */ + if (ptr3) + { + ptr3->next = ptr2->next; + g_free (ptr2); + ptr2 = NULL; + } + else + { + spans[j] = ptr2->next; + g_free (ptr2); + ptr2 = NULL; + } + break; + } + /* gone past the span point no point looking */ + else if (ptr2->start < ptr1->start) + break; + if (ptr2) + { + ptr3 = ptr2; + ptr2 = ptr2->next; + } + } + /* if a contiguous span was found increase the rect h */ + if (contig) + { + rects[num_rects].height++; + j++; + } + } + /* up the rect count */ + num_rects++; + /* every 256 new rects increase the rect array */ + if ((num_rects % 256) == 0) + rects = g_realloc (rects, sizeof (XRectangle) * (num_rects + 256)); + ptr1 = ptr1->next; + } + } + /* set the rects as the shape mask */ + if (rects) + { + XShapeCombineRectangles (disp, win, ShapeBounding, 0, 0, rects, num_rects, + ShapeSet, YXSorted); + g_free (rects); + } + XFree (list); + } + /* free up all the spans we made */ + for (i = 0; i < baseh; i++) + { + ptr1 = spans[i]; + while (ptr1) + { + ptr2 = ptr1; + ptr1 = ptr1->next; + g_free (ptr2); + } + } + g_free (spans); +} + +#endif /* HAVE_SHAPE_EXT */ + +/** + * gdk_window_set_child_shapes: + * @window: a #GdkWindow + * + * Sets the shape mask of @window to the union of shape masks + * for all children of @window, ignoring the shape mask of @window + * itself. Contrast with gdk_window_merge_child_shapes() which includes + * the shape mask of @window in the masks to be merged. + **/ +void +gdk_window_set_child_shapes (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + +#ifdef HAVE_SHAPE_EXT + if (!GDK_WINDOW_DESTROYED (window) && + gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window))) + gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), FALSE); +#endif +} + +/** + * gdk_window_merge_child_shapes: + * @window: a #GdkWindow + * + * Merges the shape masks for any child windows into the + * shape mask for @window. i.e. the union of all masks + * for @window and its children will become the new mask + * for @window. See gdk_window_shape_combine_mask(). + * + * This function is distinct from gdk_window_set_child_shapes() + * because it includes @window's shape mask in the set of shapes to + * be merged. + * + **/ +void +gdk_window_merge_child_shapes (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + +#ifdef HAVE_SHAPE_EXT + if (!GDK_WINDOW_DESTROYED (window) && + gdk_window_have_shape_ext (GDK_WINDOW_DISPLAY (window))) + gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), TRUE); +#endif +} + +static void +gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on) +{ + XSetWindowAttributes xattributes; + GdkWindowObject *private; + guint xattributes_mask = 0; + + g_return_if_fail (window != NULL); + + private = GDK_WINDOW_OBJECT (window); + if (private->input_only) + return; + + xattributes.bit_gravity = StaticGravity; + xattributes_mask |= CWBitGravity; + xattributes.bit_gravity = on ? StaticGravity : ForgetGravity; + XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + CWBitGravity, &xattributes); +} + +static void +gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on) +{ + XSetWindowAttributes xattributes; + + g_return_if_fail (window != NULL); + + xattributes.win_gravity = on ? StaticGravity : NorthWestGravity; + + XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + CWWinGravity, &xattributes); +} + +/** + * gdk_window_set_static_gravities: + * @window: a #GdkWindow + * @use_static: %TRUE to turn on static gravity + * + * Set the bit gravity of the given window to static, and flag it so + * all children get static subwindow gravity. This is used if you are + * implementing scary features that involve deep knowledge of the + * windowing system. Don't worry about it unless you have to. + * + * Return value: %TRUE if the server supports static gravity + **/ +gboolean +gdk_window_set_static_gravities (GdkWindow *window, + gboolean use_static) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GList *tmp_list; + + g_return_val_if_fail (window != NULL, FALSE); + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + if (!use_static == !private->guffaw_gravity) + return TRUE; + + private->guffaw_gravity = use_static; + + if (!GDK_WINDOW_DESTROYED (window)) + { + gdk_window_set_static_bit_gravity (window, use_static); + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_set_static_win_gravity (tmp_list->data, use_static); + + tmp_list = tmp_list->next; + } + } + + return TRUE; +} + +static void +wmspec_moveresize (GdkWindow *window, + gint direction, + gint root_x, + gint root_y, + guint32 timestamp) +{ + GdkDisplay *display = GDK_WINDOW_DISPLAY (window); + + XEvent xev; + + /* Release passive grab */ + gdk_display_pointer_ungrab (display, timestamp); + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = GDK_WINDOW_XID (window); + xev.xclient.message_type = + gdk_macosx_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE"); + xev.xclient.format = 32; + xev.xclient.data.l[0] = root_x; + xev.xclient.data.l[1] = root_y; + xev.xclient.data.l[2] = direction; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +typedef struct _MoveResizeData MoveResizeData; + +struct _MoveResizeData +{ + GdkDisplay *display; + + GdkWindow *moveresize_window; + GdkWindow *moveresize_emulation_window; + gboolean is_resize; + GdkWindowEdge resize_edge; + gint moveresize_button; + gint moveresize_x; + gint moveresize_y; + gint moveresize_orig_x; + gint moveresize_orig_y; + gint moveresize_orig_width; + gint moveresize_orig_height; + GdkWindowHints moveresize_geom_mask; + GdkGeometry moveresize_geometry; + Time moveresize_process_time; + XEvent *moveresize_pending_event; +}; + +/* From the WM spec */ +#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 + +static void +wmspec_resize_drag (GdkWindow *window, + GdkWindowEdge edge, + gint button, + gint root_x, + gint root_y, + guint32 timestamp) +{ + gint direction; + + /* Let the compiler turn a switch into a table, instead + * of doing the table manually, this way is easier to verify. + */ + switch (edge) + { + case GDK_WINDOW_EDGE_NORTH_WEST: + direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT; + break; + + case GDK_WINDOW_EDGE_NORTH: + direction = _NET_WM_MOVERESIZE_SIZE_TOP; + break; + + case GDK_WINDOW_EDGE_NORTH_EAST: + direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT; + break; + + case GDK_WINDOW_EDGE_WEST: + direction = _NET_WM_MOVERESIZE_SIZE_LEFT; + break; + + case GDK_WINDOW_EDGE_EAST: + direction = _NET_WM_MOVERESIZE_SIZE_RIGHT; + break; + + case GDK_WINDOW_EDGE_SOUTH_WEST: + direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; + break; + + case GDK_WINDOW_EDGE_SOUTH: + direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM; + break; + + case GDK_WINDOW_EDGE_SOUTH_EAST: + direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; + break; + + default: + g_warning ("gdk_window_begin_resize_drag: bad resize edge %d!", + edge); + return; + break; + } + + wmspec_moveresize (window, direction, root_x, root_y, timestamp); +} + +static MoveResizeData * +get_move_resize_data (GdkDisplay *display, + gboolean create) +{ + MoveResizeData *mv_resize; + static GQuark move_resize_quark = 0; + + if (!move_resize_quark) + move_resize_quark = g_quark_from_static_string ("gdk-window-moveresize"); + + mv_resize = g_object_get_qdata (G_OBJECT (display), move_resize_quark); + + if (!mv_resize && create) + { + mv_resize = g_new0 (MoveResizeData, 1); + mv_resize->display = display; + + g_object_set_qdata (G_OBJECT (display), move_resize_quark, mv_resize); + } + + return mv_resize; +} + +static void +update_pos (MoveResizeData *mv_resize, + gint new_root_x, + gint new_root_y) +{ + gint dx, dy; + + dx = new_root_x - mv_resize->moveresize_x; + dy = new_root_y - mv_resize->moveresize_y; + + if (mv_resize->is_resize) + { + gint x, y, w, h; + + x = mv_resize->moveresize_orig_x; + y = mv_resize->moveresize_orig_y; + + w = mv_resize->moveresize_orig_width; + h = mv_resize->moveresize_orig_height; + + switch (mv_resize->resize_edge) + { + case GDK_WINDOW_EDGE_NORTH_WEST: + x += dx; + y += dy; + w -= dx; + h -= dy; + break; + case GDK_WINDOW_EDGE_NORTH: + y += dy; + h -= dy; + break; + case GDK_WINDOW_EDGE_NORTH_EAST: + y += dy; + h -= dy; + w += dx; + break; + case GDK_WINDOW_EDGE_SOUTH_WEST: + h += dy; + x += dx; + w -= dx; + break; + case GDK_WINDOW_EDGE_SOUTH_EAST: + w += dx; + h += dy; + break; + case GDK_WINDOW_EDGE_SOUTH: + h += dy; + break; + case GDK_WINDOW_EDGE_EAST: + w += dx; + break; + case GDK_WINDOW_EDGE_WEST: + x += dx; + w -= dx; + break; + } + + x = MAX (x, 0); + y = MAX (y, 0); + w = MAX (w, 1); + h = MAX (h, 1); + + if (mv_resize->moveresize_geom_mask) + { + gdk_window_constrain_size (&mv_resize->moveresize_geometry, + mv_resize->moveresize_geom_mask, + w, h, &w, &h); + } + + gdk_window_move_resize (mv_resize->moveresize_window, x, y, w, h); + } + else + { + gint x, y; + + x = mv_resize->moveresize_orig_x + dx; + y = mv_resize->moveresize_orig_y + dy; + + gdk_window_move (mv_resize->moveresize_window, x, y); + } +} + +static void +finish_drag (MoveResizeData *mv_resize) +{ + gdk_window_destroy (mv_resize->moveresize_emulation_window); + mv_resize->moveresize_emulation_window = NULL; + mv_resize->moveresize_window = NULL; + + if (mv_resize->moveresize_pending_event) + { + g_free (mv_resize->moveresize_pending_event); + mv_resize->moveresize_pending_event = NULL; + } +} + +static int +lookahead_motion_predicate (Display *xdisplay, + XEvent *event, + XPointer arg) +{ + gboolean *seen_release = (gboolean *)arg; + GdkDisplay *display = gdk_macosx_lookup_xdisplay (xdisplay); + MoveResizeData *mv_resize = get_move_resize_data (display, FALSE); + + if (*seen_release) + return False; + + switch (event->xany.type) + { + case ButtonRelease: + *seen_release = TRUE; + break; + case MotionNotify: + mv_resize->moveresize_process_time = event->xmotion.time; + break; + default: + break; + } + + return False; +} + +static gboolean +moveresize_lookahead (MoveResizeData *mv_resize, + XEvent *event) +{ + XEvent tmp_event; + gboolean seen_release = FALSE; + + if (mv_resize->moveresize_process_time) + { + if (event->xmotion.time == mv_resize->moveresize_process_time) + { + mv_resize->moveresize_process_time = 0; + return TRUE; + } + else + return FALSE; + } + + XCheckIfEvent (event->xany.display, &tmp_event, + lookahead_motion_predicate, (XPointer) & seen_release); + + return mv_resize->moveresize_process_time == 0; +} + +gboolean +_gdk_moveresize_handle_event (XEvent *event) +{ + guint button_mask = 0; + GdkWindowObject *window_private; + GdkDisplay *display = gdk_macosx_lookup_xdisplay (event->xany.display); + MoveResizeData *mv_resize = get_move_resize_data (display, FALSE); + + if (!mv_resize || !mv_resize->moveresize_window) + return FALSE; + + window_private = (GdkWindowObject *) mv_resize->moveresize_window; + + button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1); + + switch (event->xany.type) + { + case MotionNotify: + if (window_private->resize_count > 0) + { + if (mv_resize->moveresize_pending_event) + *mv_resize->moveresize_pending_event = *event; + else + mv_resize->moveresize_pending_event = + g_memdup (event, sizeof (XEvent)); + + break; + } + if (!moveresize_lookahead (mv_resize, event)) + break; + + update_pos (mv_resize, + event->xmotion.x_root, + event->xmotion.y_root); + + /* This should never be triggered in normal cases, but in the + * case where the drag started without an implicit grab being + * in effect, we could miss the release if it occurs before + * we grab the pointer; this ensures that we will never + * get a permanently stuck grab. + */ + if ((event->xmotion.state & button_mask) == 0) + finish_drag (mv_resize); + break; + + case ButtonRelease: + update_pos (mv_resize, + event->xbutton.x_root, + event->xbutton.y_root); + + if (event->xbutton.button == mv_resize->moveresize_button) + finish_drag (mv_resize); + break; + } + return TRUE; +} + +gboolean +_gdk_moveresize_configure_done (GdkDisplay *display, + GdkWindow *window) +{ + XEvent *tmp_event; + MoveResizeData *mv_resize = get_move_resize_data (display, FALSE); + + if (!mv_resize || window != mv_resize->moveresize_window) + return FALSE; + + if (mv_resize->moveresize_pending_event) + { + tmp_event = mv_resize->moveresize_pending_event; + mv_resize->moveresize_pending_event = NULL; + _gdk_moveresize_handle_event (tmp_event); + g_free (tmp_event); + } + + return TRUE; +} + +static void +create_moveresize_window (MoveResizeData *mv_resize, + guint32 timestamp) +{ + GdkWindowAttr attributes; + gint attributes_mask; + GdkGrabStatus status; + + g_assert (mv_resize->moveresize_emulation_window == NULL); + + attributes.x = -100; + attributes.y = -100; + attributes.width = 10; + attributes.height = 10; + attributes.window_type = GDK_WINDOW_TEMP; + attributes.wclass = GDK_INPUT_ONLY; + attributes.override_redirect = TRUE; + attributes.event_mask = 0; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR; + + mv_resize->moveresize_emulation_window = + gdk_window_new (gdk_screen_get_root_window (gdk_display_get_default_screen (mv_resize->display)), + &attributes, + attributes_mask); + + gdk_window_show (mv_resize->moveresize_emulation_window); + + status = gdk_pointer_grab (mv_resize->moveresize_emulation_window, + FALSE, + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK, + NULL, + NULL, + timestamp); + + if (status != GDK_GRAB_SUCCESS) + { + /* If this fails, some other client has grabbed the window + * already. + */ + gdk_window_destroy (mv_resize->moveresize_emulation_window); + mv_resize->moveresize_emulation_window = NULL; + } + + mv_resize->moveresize_process_time = 0; +} + +/* + Calculate mv_resize->moveresize_orig_x and mv_resize->moveresize_orig_y + so that calling XMoveWindow with these coordinates will not move the + window. + Note that this depends on the WM to implement ICCCM-compliant reference + point handling. +*/ +static void +calculate_unmoving_origin (MoveResizeData *mv_resize) +{ + GdkRectangle rect; + gint width, height; + + if (mv_resize->moveresize_geom_mask & GDK_HINT_WIN_GRAVITY && + mv_resize->moveresize_geometry.win_gravity == GDK_GRAVITY_STATIC) + { + gdk_window_get_origin (mv_resize->moveresize_window, + &mv_resize->moveresize_orig_x, + &mv_resize->moveresize_orig_y); + } + else + { + gdk_window_get_frame_extents (mv_resize->moveresize_window, &rect); + gdk_window_get_geometry (mv_resize->moveresize_window, + NULL, NULL, &width, &height, NULL); + + switch (mv_resize->moveresize_geometry.win_gravity) + { + case GDK_GRAVITY_NORTH_WEST: + mv_resize->moveresize_orig_x = rect.x; + mv_resize->moveresize_orig_y = rect.y; + break; + case GDK_GRAVITY_NORTH: + mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2; + mv_resize->moveresize_orig_y = rect.y; + break; + case GDK_GRAVITY_NORTH_EAST: + mv_resize->moveresize_orig_x = rect.x + rect.width - width; + mv_resize->moveresize_orig_y = rect.y; + break; + case GDK_GRAVITY_WEST: + mv_resize->moveresize_orig_x = rect.x; + mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2; + break; + case GDK_GRAVITY_CENTER: + mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2; + mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2; + break; + case GDK_GRAVITY_EAST: + mv_resize->moveresize_orig_x = rect.x + rect.width - width; + mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2; + break; + case GDK_GRAVITY_SOUTH_WEST: + mv_resize->moveresize_orig_x = rect.x; + mv_resize->moveresize_orig_y = rect.y + rect.height - height; + break; + case GDK_GRAVITY_SOUTH: + mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2; + mv_resize->moveresize_orig_y = rect.y + rect.height - height; + break; + case GDK_GRAVITY_SOUTH_EAST: + mv_resize->moveresize_orig_x = rect.x + rect.width - width; + mv_resize->moveresize_orig_y = rect.y + rect.height - height; + break; + default: + mv_resize->moveresize_orig_x = rect.x; + mv_resize->moveresize_orig_y = rect.y; + break; + } + } +} + +static void +emulate_resize_drag (GdkWindow *window, + GdkWindowEdge edge, + gint button, + gint root_x, + gint root_y, + guint32 timestamp) +{ + MoveResizeData *mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window), TRUE); + + mv_resize->is_resize = TRUE; + mv_resize->moveresize_button = button; + mv_resize->resize_edge = edge; + mv_resize->moveresize_x = root_x; + mv_resize->moveresize_y = root_y; + mv_resize->moveresize_window = g_object_ref (window); + + gdk_drawable_get_size (window, + &mv_resize->moveresize_orig_width, + &mv_resize->moveresize_orig_height); + + mv_resize->moveresize_geom_mask = 0; + gdk_window_get_geometry_hints (window, + &mv_resize->moveresize_geometry, + &mv_resize->moveresize_geom_mask); + + calculate_unmoving_origin (mv_resize); + + create_moveresize_window (mv_resize, timestamp); +} + +static void +emulate_move_drag (GdkWindow *window, + gint button, + gint root_x, + gint root_y, + guint32 timestamp) +{ + MoveResizeData *mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window), TRUE); + + mv_resize->is_resize = FALSE; + mv_resize->moveresize_button = button; + mv_resize->moveresize_x = root_x; + mv_resize->moveresize_y = root_y; + + mv_resize->moveresize_window = g_object_ref (window); + + calculate_unmoving_origin (mv_resize); + + create_moveresize_window (mv_resize, timestamp); +} + +/** + * gdk_window_begin_resize_drag: + * @window: a toplevel #GdkWindow + * @edge: the edge or corner from which the drag is started + * @button: the button being used to drag + * @root_x: root window X coordinate of mouse click that began the drag + * @root_y: root window Y coordinate of mouse click that began the drag + * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time()) + * + * Begins a window resize operation (for a toplevel window). + * You might use this function to implement a "window resize grip," for + * example; in fact #GtkStatusbar uses it. The function works best + * with window managers that support the Extended Window Manager Hints spec + * (see http://www.freedesktop.org), but has a fallback implementation + * for other window managers. + * + **/ +void +gdk_window_begin_resize_drag (GdkWindow *window, + GdkWindowEdge edge, + gint button, + gint root_x, + gint root_y, + guint32 timestamp) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (gdk_macosx_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window), + gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE))) + wmspec_resize_drag (window, edge, button, root_x, root_y, timestamp); + else + emulate_resize_drag (window, edge, button, root_x, root_y, timestamp); +} + +/** + * gdk_window_begin_move_drag: + * @window: a toplevel #GdkWindow + * @button: the button being used to drag + * @root_x: root window X coordinate of mouse click that began the drag + * @root_y: root window Y coordinate of mouse click that began the drag + * @timestamp: timestamp of mouse click that began the drag + * + * Begins a window move operation (for a toplevel window). You might + * use this function to implement a "window move grip," for + * example. The function works best with window managers that support + * the Extended Window Manager Hints spec (see + * http://www.freedesktop.org), but has a fallback implementation for + * other window managers. + * + **/ +void +gdk_window_begin_move_drag (GdkWindow *window, + gint button, + gint root_x, + gint root_y, + guint32 timestamp) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (gdk_macosx_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window), + gdk_atom_intern ("_NET_WM_MOVERESIZE", FALSE))) + wmspec_moveresize (window, _NET_WM_MOVERESIZE_MOVE, root_x, root_y, + timestamp); + else + emulate_move_drag (window, button, root_x, root_y, timestamp); +} + +/** + * gdk_window_enable_synchronized_configure: + * @window: a toplevel #GdkWindow + * + * Indicates that the application will cooperate with the window + * system in synchronizing the window repaint with the window + * manager during resizing operations. After an application calls + * this function, it must call gdk_window_configure_finished() every + * time it has finished all processing associated with a set of + * Configure events. Toplevel GTK+ windows automatically use this + * protocol. + * + * On X, calling this function makes @window participate in the + * _NET_WM_SYNC_REQUEST window manager protocol. + * + * Since: 2.6 + **/ +void +gdk_window_enable_synchronized_configure (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *)window; + GdkWindowImplMacOSX *impl; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + impl = GDK_WINDOW_IMPL_MACOSX (private->impl); + + if (!impl->use_synchronized_configure) + { + impl->use_synchronized_configure = TRUE; + ensure_sync_counter (window); + } +} + +/** + * gdk_window_configure_finished: + * @window: a toplevel #GdkWindow + * + * Signal to the window system that the application has finished + * handling Configure events it has received. Window Managers can + * use this to better synchronize the frame repaint with the + * application. GTK+ applications will automatically call this + * function when appropriate. + * + * This function can only be called if gdk_window_enable_synchronized_configure() + * was called previously. + * + * Since: 2.6 + **/ +void +gdk_window_configure_finished (GdkWindow *window) +{ + GdkWindowImplMacOSX *impl; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + impl = GDK_WINDOW_IMPL_MACOSX (((GdkWindowObject *)window)->impl); + if (!impl->use_synchronized_configure) + return; + +#ifdef HAVE_XSYNC + if (!GDK_WINDOW_DESTROYED (window)) + { + GdkDisplay *display = GDK_WINDOW_DISPLAY (window); + GdkToplevelMacOSX *toplevel = _gdk_macosx_window_get_toplevel (window); + + if (toplevel && toplevel->update_counter != None && + GDK_DISPLAY_MACOSX (display)->use_sync && + !XSyncValueIsZero (toplevel->current_counter_value)) + { + XSyncSetCounter (GDK_WINDOW_XDISPLAY (window), + toplevel->update_counter, + toplevel->current_counter_value); + + XSyncIntToValue (&toplevel->current_counter_value, 0); + } + } +#endif +} + + +#endif + +void +_gdk_window_init_position (GdkWindow *window) +{ + +} diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 623df1cb39..bc30bdd882 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -658,20 +658,23 @@ gtkinclude_HEADERS = $(gtk_public_h_sources) $(gtk_semi_private_h_sources) $(gtk libgtk_x11_2_0_la_SOURCES = $(gtk_c_sources) $(gtk_plug_c_sources) libgtk_linux_fb_2_0_la_SOURCES = $(gtk_c_sources) libgtk_win32_2_0_la_SOURCES = $(gtk_c_sources) +libgtk_macosx_2_0_la_SOURCES = $(gtk_c_sources) libgtk_x11_2_0_la_LDFLAGS = $(libtool_opts) libgtk_linux_fb_2_0_la_LDFLAGS = $(libtool_opts) libgtk_win32_2_0_la_LDFLAGS = $(libtool_opts) +libgtk_macosx_2_0_la_LDFLAGS = $(libtool_opts) libgtk_x11_2_0_la_LIBADD = $(libadd) libgtk_linux_fb_2_0_la_LIBADD = $(libadd) libgtk_win32_2_0_la_LIBADD = $(libadd) $(gtk_win32res_lo) -lole32 -lwsock32 -lgdi32 libgtk_win32_2_0_la_DEPENDENCIES = $(gtk_def) $(gtk_win32res_lo) +libgtk_macosx_2_0_la_LIBADD = $(libadd) if USE_WIN32 libgtk_target_ldflags = $(gtk_win32_symbols) endif -EXTRA_LTLIBRARIES = libgtk-x11-2.0.la libgtk-linux-fb-2.0.la libgtk-win32-2.0.la +EXTRA_LTLIBRARIES = libgtk-x11-2.0.la libgtk-linux-fb-2.0.la libgtk-win32-2.0.la libgtk-macosx-2.0.la install-exec-hook: if DISABLE_EXPLICIT_DEPS |