1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1998-2002 Tor Lillqvist
4 * Copyright (C) 2001,2009 Hans Breuer
5 * Copyright (C) 2007-2009 Cody Russell
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
25 * file for a list of people on the GTK+ Team. See the ChangeLog
26 * files for a list of changes. These files are distributed with
27 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 /* Cannot use TrackMouseEvent, as the stupid WM_MOUSELEAVE message
31 * doesn't tell us where the mouse has gone. Thus we cannot use it to
32 * generate a correct GdkNotifyType. Pity, as using TrackMouseEvent
33 * otherwise would make it possible to reliably generate
34 * GDK_LEAVE_NOTIFY events, which would help get rid of those pesky
35 * tooltips sometimes popping up in the wrong place.
37 * Update: a combination of TrackMouseEvent, GetCursorPos and
38 * GetWindowPos can and is actually used to get rid of those
39 * pesky tooltips. It should be possible to use this for the
40 * whole ENTER/LEAVE NOTIFY handling but some platforms may
41 * not have TrackMouseEvent at all (?) --hb
46 #include <glib/gprintf.h>
49 #include "gdkdisplayprivate.h"
50 #include "gdkprivate-win32.h"
52 #include "gdkkeysyms.h"
53 #include "gdkdevicemanager-win32.h"
54 #include "gdkdeviceprivate.h"
55 #include "gdkdevice-wintab.h"
56 #include "gdkwin32dnd.h"
57 #include "gdkdndprivate.h"
81 #define MK_XBUTTON1 32
82 #define MK_XBUTTON2 64
86 * Private function declarations
89 static gboolean gdk_event_translate (MSG *msg,
91 static void handle_wm_paint (MSG *msg,
93 gboolean return_exposes,
96 static gboolean gdk_event_prepare (GSource *source,
98 static gboolean gdk_event_check (GSource *source);
99 static gboolean gdk_event_dispatch (GSource *source,
100 GSourceFunc callback,
103 static void append_event (GdkEvent *event);
104 static gboolean is_modally_blocked (GdkWindow *window);
106 /* Private variable declarations
109 static GList *client_filters; /* Filters for client messages */
110 extern gint _gdk_input_ignore_core;
112 static HCURSOR p_grab_cursor;
114 static GSourceFuncs event_funcs = {
121 GPollFD event_poll_fd;
123 static GdkWindow *current_toplevel = NULL;
124 static gint current_x, current_y;
125 static gint current_root_x, current_root_y;
126 static UINT client_message;
128 static UINT got_gdk_events_message;
129 static HWND modal_win32_dialog = NULL;
132 static HKL latin_locale = NULL;
135 static gboolean in_ime_composition = FALSE;
136 static UINT modal_timer;
137 static UINT sync_timer = 0;
139 static int debug_indent = 0;
142 synthesize_enter_or_leave_event (GdkWindow *window,
145 GdkCrossingMode mode,
146 GdkNotifyType detail);
149 assign_object (gpointer lhsp,
152 if (*(gpointer *)lhsp != rhs)
154 if (*(gpointer *)lhsp != NULL)
155 g_object_unref (*(gpointer *)lhsp);
156 *(gpointer *)lhsp = rhs;
163 track_mouse_event (DWORD dwFlags,
168 tme.cbSize = sizeof(TRACKMOUSEEVENT);
169 tme.dwFlags = dwFlags;
170 tme.hwndTrack = hwnd;
171 tme.dwHoverTime = HOVER_DEFAULT; /* not used */
173 if (!TrackMouseEvent (&tme))
174 WIN32_API_FAILED ("TrackMouseEvent");
175 else if (dwFlags == TME_LEAVE)
176 GDK_NOTE (EVENTS, g_print(" (TrackMouseEvent %p)", hwnd));
177 else if (dwFlags == TME_CANCEL)
178 GDK_NOTE (EVENTS, g_print(" (cancel TrackMouseEvent %p)", hwnd));
182 _gdk_win32_get_next_tick (gulong suggested_tick)
184 static gulong cur_tick = 0;
186 if (suggested_tick == 0)
187 suggested_tick = GetTickCount ();
188 if (suggested_tick <= cur_tick)
191 return cur_tick = suggested_tick;
195 generate_focus_event (GdkDeviceManager *device_manager,
202 device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
204 event = gdk_event_new (GDK_FOCUS_CHANGE);
205 event->focus_change.window = window;
206 event->focus_change.in = in;
207 gdk_event_set_device (event, device);
209 append_event (event);
213 generate_grab_broken_event (GdkDeviceManager *device_manager,
216 GdkWindow *grab_window)
218 GdkEvent *event = gdk_event_new (GDK_GRAB_BROKEN);
222 device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
224 device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_pointer;
226 event->grab_broken.window = window;
227 event->grab_broken.send_event = 0;
228 event->grab_broken.keyboard = keyboard;
229 event->grab_broken.implicit = FALSE;
230 event->grab_broken.grab_window = grab_window;
231 gdk_event_set_device (event, device);
233 append_event (event);
237 inner_window_procedure (HWND hwnd,
247 msg.message = message;
250 msg.time = _gdk_win32_get_next_tick (0);
251 pos = GetMessagePos ();
252 msg.pt.x = GET_X_LPARAM (pos);
253 msg.pt.y = GET_Y_LPARAM (pos);
255 if (gdk_event_translate (&msg, &ret_val))
257 /* If gdk_event_translate() returns TRUE, we return ret_val from
258 * the window procedure.
260 if (modal_win32_dialog)
261 PostMessageW (modal_win32_dialog, got_gdk_events_message,
267 /* Otherwise call DefWindowProcW(). */
268 GDK_NOTE (EVENTS, g_print (" DefWindowProcW"));
269 return DefWindowProcW (hwnd, message, wparam, lparam);
274 _gdk_win32_window_procedure (HWND hwnd,
281 GDK_NOTE (EVENTS, g_print ("%s%*s%s %p",
282 (debug_indent > 0 ? "\n" : ""),
284 _gdk_win32_message_to_string (message), hwnd));
286 retval = inner_window_procedure (hwnd, message, wparam, lparam);
289 GDK_NOTE (EVENTS, g_print (" => %I64d%s", (gint64) retval, (debug_indent == 0 ? "\n" : "")));
295 _gdk_events_init (void)
302 /* List of languages that use a latin keyboard. Somewhat sorted in
303 * "order of least surprise", in case we have to load one of them if
304 * the user only has arabic loaded, for instance.
306 static int latin_languages[] = {
312 /* Rest in numeric order */
341 client_message = RegisterWindowMessage ("GDK_WIN32_CLIENT_MESSAGE");
342 got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
345 /* Check if we have some input locale identifier loaded that uses a
346 * latin keyboard, to be able to get the virtual-key code for the
347 * latin characters corresponding to ASCII control characters.
349 if ((n = GetKeyboardLayoutList (0, NULL)) == 0)
350 WIN32_API_FAILED ("GetKeyboardLayoutList");
353 HKL *hkl_list = g_new (HKL, n);
354 if (GetKeyboardLayoutList (n, hkl_list) == 0)
355 WIN32_API_FAILED ("GetKeyboardLayoutList");
358 for (i = 0; latin_locale == NULL && i < n; i++)
359 for (j = 0; j < G_N_ELEMENTS (latin_languages); j++)
360 if (PRIMARYLANGID (LOWORD (hkl_list[i])) == latin_languages[j])
362 latin_locale = hkl_list [i];
369 if (latin_locale == NULL)
371 /* Try to load a keyboard layout with latin characters then.
374 while (latin_locale == NULL && i < G_N_ELEMENTS (latin_languages))
377 g_sprintf (id, "%08x", MAKELANGID (latin_languages[i++], SUBLANG_DEFAULT));
378 latin_locale = LoadKeyboardLayout (id, KLF_NOTELLSHELL|KLF_SUBSTITUTE_OK);
382 GDK_NOTE (EVENTS, g_print ("latin_locale = %08x\n", (guint) latin_locale));
385 source = g_source_new (&event_funcs, sizeof (GSource));
386 g_source_set_name (source, "GDK Win32 event source");
387 g_source_set_priority (source, GDK_PRIORITY_EVENTS);
390 event_poll_fd.fd = open ("/dev/windows", O_RDONLY);
391 if (event_poll_fd.fd == -1)
392 g_error ("can't open \"/dev/windows\": %s", g_strerror (errno));
394 event_poll_fd.fd = G_WIN32_MSG_HANDLE;
396 event_poll_fd.events = G_IO_IN;
398 g_source_add_poll (source, &event_poll_fd);
399 g_source_set_can_recurse (source, TRUE);
400 g_source_attach (source, NULL);
404 _gdk_win32_display_has_pending (GdkDisplay *display)
407 return (_gdk_event_queue_find_first (display) ||
408 (modal_win32_dialog == NULL &&
409 PeekMessageW (&msg, NULL, 0, 0, PM_NOREMOVE)));
412 #if 0 /* Unused, but might be useful to re-introduce in some debugging output? */
415 event_mask_string (GdkEventMask mask)
417 static char bfr[500];
422 if (mask & GDK_##x##_MASK) \
423 p += g_sprintf (p, "%s" #x, (p > bfr ? " " : ""))
425 BIT (POINTER_MOTION);
426 BIT (POINTER_MOTION_HINT);
428 BIT (BUTTON1_MOTION);
429 BIT (BUTTON2_MOTION);
430 BIT (BUTTON3_MOTION);
432 BIT (BUTTON_RELEASE);
439 BIT (PROPERTY_CHANGE);
440 BIT (VISIBILITY_NOTIFY);
453 _gdk_windowing_device_grab (GdkDevice *device,
455 GdkWindow *native_window,
456 gboolean owner_events,
457 GdkEventMask event_mask,
458 GdkWindow *confine_to,
463 GdkWin32Cursor *cursor_private;
465 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (native_window->impl);
467 g_return_val_if_fail (window != NULL, 0);
468 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
469 g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
471 cursor_private = (GdkWin32Cursor*) cursor;
475 else if ((hcursor = CopyCursor (cursor_private->hcursor)) == NULL)
476 WIN32_API_FAILED ("CopyCursor");
478 return_val = GDK_DEVICE_GET_CLASS (device)->grab (device,
486 /* TODO_CSW: grab brokens, confine window, input_grab */
487 if (p_grab_cursor != NULL)
489 if (GetCursor () == p_grab_cursor)
491 DestroyCursor (p_grab_cursor);
494 p_grab_cursor = hcursor;
496 if (p_grab_cursor != NULL)
497 SetCursor (p_grab_cursor);
498 else if (impl->hcursor != NULL)
499 SetCursor (impl->hcursor);
501 SetCursor (LoadCursor (NULL, IDC_ARROW));
507 find_window_for_mouse_event (GdkWindow* reported_window,
513 GdkWindow* other_window = NULL;
514 GdkDeviceManagerWin32 *device_manager;
516 device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (_gdk_display));
518 if (!_gdk_display_get_last_device_grab (_gdk_display, device_manager->core_pointer))
519 return reported_window;
521 points = MAKEPOINTS (msg->lParam);
524 ClientToScreen (msg->hwnd, &pt);
526 hwnd = WindowFromPoint (pt);
532 GetClientRect (hwnd, &rect);
533 ScreenToClient (hwnd, &pt);
534 if (!PtInRect (&rect, pt))
537 other_window = gdk_win32_handle_table_lookup (hwnd);
540 if (other_window == NULL)
543 /* need to also adjust the coordinates to the new window */
546 ClientToScreen (msg->hwnd, &pt);
547 ScreenToClient (GDK_WINDOW_HWND (other_window), &pt);
548 /* ATTENTION: need to update client coords */
549 msg->lParam = MAKELPARAM (pt.x, pt.y);
555 build_key_event_state (GdkEvent *event,
558 event->key.state = 0;
560 if (key_state[VK_SHIFT] & 0x80)
561 event->key.state |= GDK_SHIFT_MASK;
563 if (key_state[VK_CAPITAL] & 0x01)
564 event->key.state |= GDK_LOCK_MASK;
566 if (key_state[VK_LBUTTON] & 0x80)
567 event->key.state |= GDK_BUTTON1_MASK;
568 if (key_state[VK_MBUTTON] & 0x80)
569 event->key.state |= GDK_BUTTON2_MASK;
570 if (key_state[VK_RBUTTON] & 0x80)
571 event->key.state |= GDK_BUTTON3_MASK;
572 if (key_state[VK_XBUTTON1] & 0x80)
573 event->key.state |= GDK_BUTTON4_MASK;
574 if (key_state[VK_XBUTTON2] & 0x80)
575 event->key.state |= GDK_BUTTON5_MASK;
577 if (_gdk_keyboard_has_altgr &&
578 (key_state[VK_LCONTROL] & 0x80) &&
579 (key_state[VK_RMENU] & 0x80))
581 event->key.group = 1;
582 event->key.state |= GDK_MOD2_MASK;
583 if (key_state[VK_RCONTROL] & 0x80)
584 event->key.state |= GDK_CONTROL_MASK;
585 if (key_state[VK_LMENU] & 0x80)
586 event->key.state |= GDK_MOD1_MASK;
590 event->key.group = 0;
591 if (key_state[VK_CONTROL] & 0x80)
592 event->key.state |= GDK_CONTROL_MASK;
593 if (key_state[VK_MENU] & 0x80)
594 event->key.state |= GDK_MOD1_MASK;
599 build_pointer_event_state (MSG *msg)
605 if (msg->wParam & MK_CONTROL)
606 state |= GDK_CONTROL_MASK;
608 if ((msg->message != WM_LBUTTONDOWN &&
609 (msg->wParam & MK_LBUTTON)) ||
610 msg->message == WM_LBUTTONUP)
611 state |= GDK_BUTTON1_MASK;
613 if ((msg->message != WM_MBUTTONDOWN &&
614 (msg->wParam & MK_MBUTTON)) ||
615 msg->message == WM_MBUTTONUP)
616 state |= GDK_BUTTON2_MASK;
618 if ((msg->message != WM_RBUTTONDOWN &&
619 (msg->wParam & MK_RBUTTON)) ||
620 msg->message == WM_RBUTTONUP)
621 state |= GDK_BUTTON3_MASK;
623 if (((msg->message != WM_XBUTTONDOWN || HIWORD (msg->wParam) != XBUTTON1) &&
624 (msg->wParam & MK_XBUTTON1)) ||
625 (msg->message == WM_XBUTTONUP && HIWORD (msg->wParam) == XBUTTON1))
626 state |= GDK_BUTTON4_MASK;
628 if (((msg->message != WM_XBUTTONDOWN || HIWORD (msg->wParam) != XBUTTON2) &&
629 (msg->wParam & MK_XBUTTON2)) ||
630 (msg->message == WM_XBUTTONUP && HIWORD (msg->wParam) == XBUTTON2))
631 state |= GDK_BUTTON5_MASK;
633 if (msg->wParam & MK_SHIFT)
634 state |= GDK_SHIFT_MASK;
636 if (GetKeyState (VK_MENU) < 0)
637 state |= GDK_MOD1_MASK;
639 if (GetKeyState (VK_CAPITAL) & 0x1)
640 state |= GDK_LOCK_MASK;
646 build_wm_ime_composition_event (GdkEvent *event,
651 event->key.time = _gdk_win32_get_next_tick (msg->time);
653 build_key_event_state (event, key_state);
655 event->key.hardware_keycode = 0; /* FIXME: What should it be? */
656 event->key.string = NULL;
657 event->key.length = 0;
658 event->key.keyval = gdk_unicode_to_keyval (wc);
661 #ifdef G_ENABLE_DEBUG
664 print_event_state (guint state)
666 #define CASE(bit) if (state & GDK_ ## bit ## _MASK) g_print (#bit " ");
684 _gdk_win32_print_event (const GdkEvent *event)
686 gchar *escaped, *kvname;
687 gchar *selection_name, *target_name, *property_name;
689 g_print ("%s%*s===> ", (debug_indent > 0 ? "\n" : ""), debug_indent, "");
690 switch (event->any.type)
692 #define CASE(x) case x: g_print (#x); break;
697 CASE (GDK_MOTION_NOTIFY);
698 CASE (GDK_BUTTON_PRESS);
699 CASE (GDK_2BUTTON_PRESS);
700 CASE (GDK_3BUTTON_PRESS);
701 CASE (GDK_BUTTON_RELEASE);
702 CASE (GDK_KEY_PRESS);
703 CASE (GDK_KEY_RELEASE);
704 CASE (GDK_ENTER_NOTIFY);
705 CASE (GDK_LEAVE_NOTIFY);
706 CASE (GDK_FOCUS_CHANGE);
707 CASE (GDK_CONFIGURE);
710 CASE (GDK_PROPERTY_NOTIFY);
711 CASE (GDK_SELECTION_CLEAR);
712 CASE (GDK_SELECTION_REQUEST);
713 CASE (GDK_SELECTION_NOTIFY);
714 CASE (GDK_PROXIMITY_IN);
715 CASE (GDK_PROXIMITY_OUT);
716 CASE (GDK_DRAG_ENTER);
717 CASE (GDK_DRAG_LEAVE);
718 CASE (GDK_DRAG_MOTION);
719 CASE (GDK_DRAG_STATUS);
720 CASE (GDK_DROP_START);
721 CASE (GDK_DROP_FINISHED);
722 CASE (GDK_CLIENT_EVENT);
723 CASE (GDK_VISIBILITY_NOTIFY);
725 CASE (GDK_WINDOW_STATE);
727 CASE (GDK_OWNER_CHANGE);
728 CASE (GDK_GRAB_BROKEN);
730 default: g_assert_not_reached ();
733 g_print (" %p ", event->any.window ? GDK_WINDOW_HWND (event->any.window) : NULL);
735 switch (event->any.type)
739 _gdk_win32_gdkrectangle_to_string (&event->expose.area),
740 event->expose.count);
742 case GDK_MOTION_NOTIFY:
743 g_print ("(%.4g,%.4g) (%.4g,%.4g) %s",
744 event->motion.x, event->motion.y,
745 event->motion.x_root, event->motion.y_root,
746 event->motion.is_hint ? "HINT " : "");
747 print_event_state (event->motion.state);
749 case GDK_BUTTON_PRESS:
750 case GDK_2BUTTON_PRESS:
751 case GDK_3BUTTON_PRESS:
752 case GDK_BUTTON_RELEASE:
753 g_print ("%d (%.4g,%.4g) (%.4g,%.4g) ",
754 event->button.button,
755 event->button.x, event->button.y,
756 event->button.x_root, event->button.y_root);
757 print_event_state (event->button.state);
760 case GDK_KEY_RELEASE:
761 if (event->key.length == 0)
762 escaped = g_strdup ("");
764 escaped = g_strescape (event->key.string, NULL);
765 kvname = gdk_keyval_name (event->key.keyval);
766 g_print ("%#.02x group:%d %s %d:\"%s\" ",
767 event->key.hardware_keycode, event->key.group,
768 (kvname ? kvname : "??"),
772 print_event_state (event->key.state);
774 case GDK_ENTER_NOTIFY:
775 case GDK_LEAVE_NOTIFY:
776 g_print ("%p (%.4g,%.4g) (%.4g,%.4g) %s %s%s",
777 event->crossing.subwindow == NULL ? NULL : GDK_WINDOW_HWND (event->crossing.subwindow),
778 event->crossing.x, event->crossing.y,
779 event->crossing.x_root, event->crossing.y_root,
780 (event->crossing.mode == GDK_CROSSING_NORMAL ? "NORMAL" :
781 (event->crossing.mode == GDK_CROSSING_GRAB ? "GRAB" :
782 (event->crossing.mode == GDK_CROSSING_UNGRAB ? "UNGRAB" :
784 (event->crossing.detail == GDK_NOTIFY_ANCESTOR ? "ANCESTOR" :
785 (event->crossing.detail == GDK_NOTIFY_VIRTUAL ? "VIRTUAL" :
786 (event->crossing.detail == GDK_NOTIFY_INFERIOR ? "INFERIOR" :
787 (event->crossing.detail == GDK_NOTIFY_NONLINEAR ? "NONLINEAR" :
788 (event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL ? "NONLINEAR_VIRTUAL" :
789 (event->crossing.detail == GDK_NOTIFY_UNKNOWN ? "UNKNOWN" :
791 event->crossing.focus ? " FOCUS" : "");
792 print_event_state (event->crossing.state);
794 case GDK_FOCUS_CHANGE:
795 g_print ("%s", (event->focus_change.in ? "IN" : "OUT"));
798 g_print ("x:%d y:%d w:%d h:%d",
799 event->configure.x, event->configure.y,
800 event->configure.width, event->configure.height);
802 case GDK_SELECTION_CLEAR:
803 case GDK_SELECTION_REQUEST:
804 case GDK_SELECTION_NOTIFY:
805 selection_name = gdk_atom_name (event->selection.selection);
806 target_name = gdk_atom_name (event->selection.target);
807 property_name = gdk_atom_name (event->selection.property);
808 g_print ("sel:%s tgt:%s prop:%s",
809 selection_name, target_name, property_name);
810 g_free (selection_name);
811 g_free (target_name);
812 g_free (property_name);
816 case GDK_DRAG_MOTION:
817 case GDK_DRAG_STATUS:
819 case GDK_DROP_FINISHED:
820 if (event->dnd.context != NULL)
821 g_print ("ctx:%p: %s %s src:%p dest:%p",
823 _gdk_win32_drag_protocol_to_string (event->dnd.context->protocol),
824 event->dnd.context->is_source ? "SOURCE" : "DEST",
825 event->dnd.context->source_window == NULL ? NULL : GDK_WINDOW_HWND (event->dnd.context->source_window),
826 event->dnd.context->dest_window == NULL ? NULL : GDK_WINDOW_HWND (event->dnd.context->dest_window));
828 case GDK_CLIENT_EVENT:
829 /* no more GdkEventClient */
832 g_print ("(%.4g,%.4g) (%.4g,%.4g) %s ",
833 event->scroll.x, event->scroll.y,
834 event->scroll.x_root, event->scroll.y_root,
835 (event->scroll.direction == GDK_SCROLL_UP ? "UP" :
836 (event->scroll.direction == GDK_SCROLL_DOWN ? "DOWN" :
837 (event->scroll.direction == GDK_SCROLL_LEFT ? "LEFT" :
838 (event->scroll.direction == GDK_SCROLL_RIGHT ? "RIGHT" :
840 print_event_state (event->scroll.state);
842 case GDK_WINDOW_STATE:
844 _gdk_win32_window_state_to_string (event->window_state.changed_mask),
845 _gdk_win32_window_state_to_string (event->window_state.new_window_state));
848 (event->setting.action == GDK_SETTING_ACTION_NEW ? "NEW" :
849 (event->setting.action == GDK_SETTING_ACTION_CHANGED ? "CHANGED" :
850 (event->setting.action == GDK_SETTING_ACTION_DELETED ? "DELETED" :
852 (event->setting.name ? event->setting.name : "NULL"));
853 case GDK_GRAB_BROKEN:
855 (event->grab_broken.keyboard ? "KEYBOARD" : "POINTER"),
856 (event->grab_broken.implicit ? "IMPLICIT" : "EXPLICIT"),
857 (event->grab_broken.grab_window ? GDK_WINDOW_HWND (event->grab_broken.grab_window) : 0));
862 g_print ("%s", (debug_indent == 0 ? "\n" : ""));
866 decode_key_lparam (LPARAM lParam)
868 static char buf[100];
871 if (HIWORD (lParam) & KF_UP)
872 p += g_sprintf (p, "KF_UP ");
873 if (HIWORD (lParam) & KF_REPEAT)
874 p += g_sprintf (p, "KF_REPEAT ");
875 if (HIWORD (lParam) & KF_ALTDOWN)
876 p += g_sprintf (p, "KF_ALTDOWN ");
877 if (HIWORD (lParam) & KF_EXTENDED)
878 p += g_sprintf (p, "KF_EXTENDED ");
879 p += g_sprintf (p, "sc:%d rep:%d", LOBYTE (HIWORD (lParam)), LOWORD (lParam));
887 fixup_event (GdkEvent *event)
889 if (event->any.window)
890 g_object_ref (event->any.window);
891 if (((event->any.type == GDK_ENTER_NOTIFY) ||
892 (event->any.type == GDK_LEAVE_NOTIFY)) &&
893 (event->crossing.subwindow != NULL))
894 g_object_ref (event->crossing.subwindow);
895 event->any.send_event = InSendMessage ();
899 append_event (GdkEvent *event)
905 link = _gdk_event_queue_append (_gdk_display, event);
906 GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
907 /* event morphing, the passed in may not be valid afterwards */
908 _gdk_windowing_got_event (_gdk_display, link, event, 0);
910 _gdk_event_queue_append (_gdk_display, event);
911 GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
916 fill_key_event_string (GdkEvent *event)
921 /* Fill in event->string crudely, since various programs
926 if (event->key.keyval != GDK_KEY_VoidSymbol)
927 c = gdk_keyval_to_unicode (event->key.keyval);
934 /* Apply the control key - Taken from Xlib
936 if (event->key.state & GDK_CONTROL_MASK)
938 if ((c >= '@' && c < '\177') || c == ' ')
942 event->key.string = g_memdup ("\0\0", 2);
943 event->key.length = 1;
946 else if (c >= '3' && c <= '7')
954 len = g_unichar_to_utf8 (c, buf);
957 event->key.string = g_locale_from_utf8 (buf, len,
958 NULL, &bytes_written,
960 if (event->key.string)
961 event->key.length = bytes_written;
963 else if (event->key.keyval == GDK_KEY_Escape)
965 event->key.length = 1;
966 event->key.string = g_strdup ("\033");
968 else if (event->key.keyval == GDK_KEY_Return ||
969 event->key.keyval == GDK_KEY_KP_Enter)
971 event->key.length = 1;
972 event->key.string = g_strdup ("\r");
975 if (!event->key.string)
977 event->key.length = 0;
978 event->key.string = g_strdup ("");
982 static GdkFilterReturn
983 apply_event_filters (GdkWindow *window,
987 GdkFilterReturn result = GDK_FILTER_CONTINUE;
992 event = gdk_event_new (GDK_NOTHING);
994 event->any.window = g_object_ref (window);
995 ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
997 /* I think GdkFilterFunc semantics require the passed-in event
998 * to already be in the queue. The filter func can generate
999 * more events and append them after it if it likes.
1001 node = _gdk_event_queue_append (_gdk_display, event);
1003 tmp_list = *filters;
1006 GdkEventFilter *filter = (GdkEventFilter *) tmp_list->data;
1009 if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0)
1011 tmp_list = tmp_list->next;
1015 filter->ref_count++;
1016 result = filter->function (msg, event, filter->data);
1018 /* get the next node after running the function since the
1019 function may add or remove a next node */
1021 tmp_list = tmp_list->next;
1023 filter->ref_count--;
1024 if (filter->ref_count == 0)
1026 *filters = g_list_remove_link (*filters, node);
1027 g_list_free_1 (node);
1031 if (result != GDK_FILTER_CONTINUE)
1035 if (result == GDK_FILTER_CONTINUE || result == GDK_FILTER_REMOVE)
1037 _gdk_event_queue_remove_link (_gdk_display, node);
1038 g_list_free_1 (node);
1039 gdk_event_free (event);
1041 else /* GDK_FILTER_TRANSLATE */
1043 ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1044 fixup_event (event);
1045 GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
1051 * On Windows, transient windows will not have their own taskbar entries.
1052 * Because of this, we must hide and restore groups of transients in both
1053 * directions. That is, all transient children must be hidden or restored
1054 * with this window, but if this window's transient owner also has a
1055 * transient owner then this window's transient owner must be hidden/restored
1056 * with this one. And etc, up the chain until we hit an ancestor that has no
1059 * It would be a good idea if applications don't chain transient windows
1060 * together. There's a limit to how much evil GTK can try to shield you
1064 show_window_recurse (GdkWindow *window, gboolean hide_window)
1066 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1067 GSList *children = impl->transient_children;
1068 GdkWindow *child = NULL;
1070 if (!impl->changing_state)
1072 impl->changing_state = TRUE;
1074 if (children != NULL)
1076 while (children != NULL)
1078 child = children->data;
1079 show_window_recurse (child, hide_window);
1081 children = g_slist_next (children);
1085 if (GDK_WINDOW_IS_MAPPED (window))
1089 if (gdk_window_get_state (window) & GDK_WINDOW_STATE_ICONIFIED)
1091 if (gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED)
1093 ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWMAXIMIZED);
1097 ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
1103 ShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
1107 impl->changing_state = FALSE;
1112 do_show_window (GdkWindow *window, gboolean hide_window)
1114 GdkWindow *tmp_window = NULL;
1115 GdkWindowImplWin32 *tmp_impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1117 if (!tmp_impl->changing_state)
1119 /* Find the top-level window in our transient chain. */
1120 while (tmp_impl->transient_owner != NULL)
1122 tmp_window = tmp_impl->transient_owner;
1123 tmp_impl = GDK_WINDOW_IMPL_WIN32 (tmp_window->impl);
1126 /* If we couldn't find one, use the window provided. */
1127 if (tmp_window == NULL)
1129 tmp_window = window;
1132 /* Recursively show/hide every window in the chain. */
1133 if (tmp_window != window)
1135 show_window_recurse (tmp_window, hide_window);
1141 synthesize_enter_or_leave_event (GdkWindow *window,
1144 GdkCrossingMode mode,
1145 GdkNotifyType detail)
1151 ScreenToClient (GDK_WINDOW_HWND (window), &pt);
1153 event = gdk_event_new (type);
1154 event->crossing.window = window;
1155 event->crossing.subwindow = NULL;
1156 event->crossing.time = _gdk_win32_get_next_tick (msg->time);
1157 event->crossing.x = pt.x;
1158 event->crossing.y = pt.y;
1159 event->crossing.x_root = msg->pt.x + _gdk_offset_x;
1160 event->crossing.y_root = msg->pt.y + _gdk_offset_y;
1161 event->crossing.mode = mode;
1162 event->crossing.detail = detail;
1163 event->crossing.focus = TRUE; /* FIXME: Set correctly */
1164 event->crossing.state = 0; /* FIXME: Set correctly */
1165 gdk_event_set_device (event, _gdk_display->core_pointer);
1167 append_event (event);
1169 if (type == GDK_ENTER_NOTIFY &&
1170 window->extension_events != 0)
1171 _gdk_device_wintab_update_window_coords (window);
1174 /* The check_extended flag controls whether to check if the windows want
1175 * events from extended input devices and if the message should be skipped
1176 * because an extended input device is active
1179 propagate (GdkWindow **window,
1181 GdkWindow *grab_window,
1182 gboolean grab_owner_events,
1184 gboolean (*doesnt_want_it) (gint mask,
1186 gboolean check_extended)
1188 if (grab_window != NULL && !grab_owner_events)
1190 /* Event source is grabbed with owner_events FALSE */
1192 /* See if the event should be ignored because an extended input
1195 if (check_extended &&
1196 grab_window->extension_events != 0 &&
1197 _gdk_input_ignore_core)
1199 GDK_NOTE (EVENTS, g_print (" (ignored for grabber)"));
1202 if ((*doesnt_want_it) (grab_mask, msg))
1204 GDK_NOTE (EVENTS, g_print (" (grabber doesn't want it)"));
1209 GDK_NOTE (EVENTS, g_print (" (to grabber)"));
1210 assign_object (window, grab_window);
1215 /* If we come here, we know that if grab_window != NULL then
1216 * grab_owner_events is TRUE
1220 if (check_extended &&
1221 (*window)->extension_events != 0 &&
1222 _gdk_input_ignore_core)
1224 GDK_NOTE (EVENTS, g_print (" (ignored)"));
1227 if ((*doesnt_want_it) ((*window)->event_mask, msg))
1229 /* Owner doesn't want it, propagate to parent. */
1230 GdkWindow *parent = gdk_window_get_parent (*window);
1231 if (parent == _gdk_root || parent == NULL)
1233 /* No parent; check if grabbed */
1234 if (grab_window != NULL)
1236 /* Event source is grabbed with owner_events TRUE */
1238 if (check_extended &&
1239 grab_window->extension_events != 0 &&
1240 _gdk_input_ignore_core)
1242 GDK_NOTE (EVENTS, g_print (" (ignored for grabber)"));
1245 if ((*doesnt_want_it) (grab_mask, msg))
1247 /* Grabber doesn't want it either */
1248 GDK_NOTE (EVENTS, g_print (" (grabber doesn't want it)"));
1254 GDK_NOTE (EVENTS, g_print (" (to grabber)"));
1255 assign_object (window, grab_window);
1261 GDK_NOTE (EVENTS, g_print (" (undelivered)"));
1267 assign_object (window, parent);
1268 /* The only branch where we actually continue the loop */
1277 doesnt_want_key (gint mask,
1280 return (((msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP) &&
1281 !(mask & GDK_KEY_RELEASE_MASK)) ||
1282 ((msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN) &&
1283 !(mask & GDK_KEY_PRESS_MASK)));
1287 doesnt_want_char (gint mask,
1290 return !(mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK));
1294 handle_configure_event (MSG *msg,
1300 GetClientRect (msg->hwnd, &client_rect);
1301 point.x = client_rect.left; /* always 0 */
1302 point.y = client_rect.top;
1304 /* top level windows need screen coords */
1305 if (gdk_window_get_parent (window) == _gdk_root)
1307 ClientToScreen (msg->hwnd, &point);
1308 point.x += _gdk_offset_x;
1309 point.y += _gdk_offset_y;
1312 window->width = client_rect.right - client_rect.left;
1313 window->height = client_rect.bottom - client_rect.top;
1315 window->x = point.x;
1316 window->y = point.y;
1318 _gdk_window_update_size (window);
1320 if (window->event_mask & GDK_STRUCTURE_MASK)
1322 GdkEvent *event = gdk_event_new (GDK_CONFIGURE);
1324 event->configure.window = window;
1326 event->configure.width = client_rect.right - client_rect.left;
1327 event->configure.height = client_rect.bottom - client_rect.top;
1329 event->configure.x = point.x;
1330 event->configure.y = point.y;
1332 append_event (event);
1337 _gdk_win32_hrgn_to_region (HRGN hrgn)
1341 cairo_region_t *result;
1345 if ((nbytes = GetRegionData (hrgn, 0, NULL)) == 0)
1347 WIN32_GDI_FAILED ("GetRegionData");
1351 rgndata = (RGNDATA *) g_malloc (nbytes);
1353 if (GetRegionData (hrgn, nbytes, rgndata) == 0)
1355 WIN32_GDI_FAILED ("GetRegionData");
1360 result = cairo_region_create ();
1361 rects = (RECT *) rgndata->Buffer;
1362 for (i = 0; i < rgndata->rdh.nCount; i++)
1366 r.x = rects[i].left;
1368 r.width = rects[i].right - r.x;
1369 r.height = rects[i].bottom - r.y;
1371 cairo_region_union_rectangle (result, &r);
1380 adjust_drag (LONG *drag,
1385 *drag = curr + ((*drag + inc/2 - curr) / inc) * inc;
1387 *drag = curr - ((curr - *drag + inc/2) / inc) * inc;
1391 handle_wm_paint (MSG *msg,
1393 gboolean return_exposes,
1396 HRGN hrgn = CreateRectRgn (0, 0, 0, 0);
1398 PAINTSTRUCT paintstruct;
1399 cairo_region_t *update_region;
1401 if (GetUpdateRgn (msg->hwnd, hrgn, FALSE) == ERROR)
1403 WIN32_GDI_FAILED ("GetUpdateRgn");
1404 DeleteObject (hrgn);
1408 hdc = BeginPaint (msg->hwnd, &paintstruct);
1410 GDK_NOTE (EVENTS, g_print (" %s %s dc %p%s",
1411 _gdk_win32_rect_to_string (&paintstruct.rcPaint),
1412 (paintstruct.fErase ? "erase" : ""),
1414 (return_exposes ? " return_exposes" : "")));
1416 EndPaint (msg->hwnd, &paintstruct);
1418 if ((paintstruct.rcPaint.right == paintstruct.rcPaint.left) ||
1419 (paintstruct.rcPaint.bottom == paintstruct.rcPaint.top))
1421 GDK_NOTE (EVENTS, g_print (" (empty paintstruct, ignored)"));
1422 DeleteObject (hrgn);
1428 if (!GDK_WINDOW_DESTROYED (window))
1430 GList *list = _gdk_display->queued_events;
1432 *event = gdk_event_new (GDK_EXPOSE);
1433 (*event)->expose.window = window;
1434 (*event)->expose.area.x = paintstruct.rcPaint.left;
1435 (*event)->expose.area.y = paintstruct.rcPaint.top;
1436 (*event)->expose.area.width = paintstruct.rcPaint.right - paintstruct.rcPaint.left;
1437 (*event)->expose.area.height = paintstruct.rcPaint.bottom - paintstruct.rcPaint.top;
1438 (*event)->expose.region = _gdk_win32_hrgn_to_region (hrgn);
1439 (*event)->expose.count = 0;
1441 while (list != NULL)
1443 GdkEventPrivate *evp = list->data;
1445 if (evp->event.any.type == GDK_EXPOSE &&
1446 evp->event.any.window == window &&
1447 !(evp->flags & GDK_EVENT_PENDING))
1448 evp->event.expose.count++;
1454 DeleteObject (hrgn);
1458 update_region = _gdk_win32_hrgn_to_region (hrgn);
1459 if (!cairo_region_is_empty (update_region))
1460 _gdk_window_invalidate_for_expose (window, update_region);
1461 cairo_region_destroy (update_region);
1463 DeleteObject (hrgn);
1466 static VOID CALLBACK
1467 modal_timer_proc (HWND hwnd,
1472 int arbitrary_limit = 1;
1474 while (_modal_operation_in_progress &&
1475 g_main_context_pending (NULL) &&
1477 g_main_context_iteration (NULL, FALSE);
1481 _gdk_win32_begin_modal_call (void)
1483 g_assert (!_modal_operation_in_progress);
1485 _modal_operation_in_progress = TRUE;
1487 modal_timer = SetTimer (NULL, 0, 10, modal_timer_proc);
1488 if (modal_timer == 0)
1489 WIN32_API_FAILED ("SetTimer");
1493 _gdk_win32_end_modal_call (void)
1495 g_assert (_modal_operation_in_progress);
1497 _modal_operation_in_progress = FALSE;
1499 if (modal_timer != 0)
1501 API_CALL (KillTimer, (NULL, modal_timer));
1506 static VOID CALLBACK
1507 sync_timer_proc (HWND hwnd,
1513 if (PeekMessageW (&message, hwnd, WM_PAINT, WM_PAINT, PM_REMOVE))
1518 RedrawWindow (hwnd, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
1520 KillTimer (hwnd, sync_timer);
1524 handle_display_change (void)
1526 _gdk_monitor_init ();
1527 _gdk_root_window_size_init ();
1528 g_signal_emit_by_name (_gdk_screen, "size_changed");
1532 generate_button_event (GdkEventType type,
1537 GdkEvent *event = gdk_event_new (type);
1539 event->button.window = window;
1540 event->button.time = _gdk_win32_get_next_tick (msg->time);
1541 event->button.x = current_x = (gint16) GET_X_LPARAM (msg->lParam);
1542 event->button.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam);
1543 event->button.x_root = msg->pt.x + _gdk_offset_x;
1544 event->button.y_root = msg->pt.y + _gdk_offset_y;
1545 event->button.axes = NULL;
1546 event->button.state = build_pointer_event_state (msg);
1547 event->button.button = button;
1548 gdk_event_set_device (event, _gdk_display->core_pointer);
1550 append_event (event);
1554 ensure_stacking_on_unminimize (MSG *msg)
1557 HWND lowest_transient = NULL;
1560 while ((rover = GetNextWindow (rover, GW_HWNDNEXT)))
1562 GdkWindow *rover_gdkw = gdk_win32_handle_table_lookup (rover);
1564 /* Checking window group not implemented yet */
1567 GdkWindowImplWin32 *rover_impl =
1568 GDK_WINDOW_IMPL_WIN32 (rover_gdkw->impl);
1570 if (GDK_WINDOW_IS_MAPPED (rover_gdkw) &&
1571 (rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY ||
1572 rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1573 rover_impl->transient_owner != NULL))
1575 lowest_transient = rover;
1579 if (lowest_transient != NULL)
1581 GDK_NOTE (EVENTS, g_print (" restacking: %p", lowest_transient));
1582 SetWindowPos (msg->hwnd, lowest_transient, 0, 0, 0, 0,
1583 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1588 ensure_stacking_on_window_pos_changing (MSG *msg,
1591 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1592 WINDOWPOS *windowpos = (WINDOWPOS *) msg->lParam;
1594 if (GetActiveWindow () == msg->hwnd &&
1595 impl->type_hint != GDK_WINDOW_TYPE_HINT_UTILITY &&
1596 impl->type_hint != GDK_WINDOW_TYPE_HINT_DIALOG &&
1597 impl->transient_owner == NULL)
1599 /* Make sure the window stays behind any transient-type windows
1600 * of the same window group.
1602 * If the window is not active and being activated, we let
1603 * Windows bring it to the top and rely on the WM_ACTIVATEAPP
1604 * handling to bring any utility windows on top of it.
1607 gboolean restacking;
1609 rover = windowpos->hwndInsertAfter;
1613 GdkWindow *rover_gdkw = gdk_win32_handle_table_lookup (rover);
1615 /* Checking window group not implemented yet */
1618 GdkWindowImplWin32 *rover_impl =
1619 GDK_WINDOW_IMPL_WIN32 (rover_gdkw->impl);
1621 if (GDK_WINDOW_IS_MAPPED (rover_gdkw) &&
1622 (rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY ||
1623 rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1624 rover_impl->transient_owner != NULL))
1627 windowpos->hwndInsertAfter = rover;
1630 rover = GetNextWindow (rover, GW_HWNDNEXT);
1635 GDK_NOTE (EVENTS, g_print (" restacking: %p", windowpos->hwndInsertAfter));
1643 ensure_stacking_on_activate_app (MSG *msg,
1646 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1648 if (impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY ||
1649 impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1650 impl->transient_owner != NULL)
1652 SetWindowPos (msg->hwnd, HWND_TOP, 0, 0, 0, 0,
1653 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1657 if (IsWindowVisible (msg->hwnd) &&
1658 msg->hwnd == GetActiveWindow ())
1660 /* This window is not a transient-type window and it is the
1661 * activated window. Make sure this window is as visible as
1662 * possible, just below the lowest transient-type window of this
1668 while ((rover = GetNextWindow (rover, GW_HWNDPREV)))
1670 GdkWindow *rover_gdkw = gdk_win32_handle_table_lookup (rover);
1672 /* Checking window group not implemented yet */
1675 GdkWindowImplWin32 *rover_impl =
1676 GDK_WINDOW_IMPL_WIN32 (rover_gdkw->impl);
1678 if (GDK_WINDOW_IS_MAPPED (rover_gdkw) &&
1679 (rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY ||
1680 rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1681 rover_impl->transient_owner != NULL))
1683 GDK_NOTE (EVENTS, g_print (" restacking: %p", rover));
1684 SetWindowPos (msg->hwnd, rover, 0, 0, 0, 0,
1685 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1694 gdk_event_translate (MSG *msg,
1697 RECT rect, *drag, orig_drag;
1702 BYTE key_state[256];
1704 WINDOWPOS *windowpos;
1711 GdkWindow *window = NULL;
1712 GdkWindowImplWin32 *impl;
1714 GdkWindow *orig_window, *new_window, *toplevel;
1716 GdkDeviceManager *device_manager;
1718 GdkDeviceGrabInfo *keyboard_grab = NULL;
1719 GdkDeviceGrabInfo *pointer_grab = NULL;
1720 GdkWindow *grab_window = NULL;
1726 gboolean return_val = FALSE;
1730 if (_gdk_default_filters)
1732 /* Apply global filters */
1734 GdkFilterReturn result = apply_event_filters (NULL, msg, &_gdk_default_filters);
1736 /* If result is GDK_FILTER_CONTINUE, we continue as if nothing
1737 * happened. If it is GDK_FILTER_REMOVE or GDK_FILTER_TRANSLATE,
1738 * we return TRUE, and DefWindowProcW() will not be called.
1740 if (result == GDK_FILTER_REMOVE || result == GDK_FILTER_TRANSLATE)
1744 window = gdk_win32_handle_table_lookup (msg->hwnd);
1745 orig_window = window;
1749 /* XXX Handle WM_QUIT here ? */
1750 if (msg->message == WM_QUIT)
1752 GDK_NOTE (EVENTS, g_print (" %d", (int) msg->wParam));
1755 else if (msg->message == WM_MOVE ||
1756 msg->message == WM_SIZE)
1758 /* It's quite normal to get these messages before we have
1759 * had time to register the window in our lookup table, or
1760 * when the window is being destroyed and we already have
1761 * removed it. Repost the same message to our queue so that
1762 * we will get it later when we are prepared.
1764 GDK_NOTE (EVENTS, g_print (" (posted)"));
1766 PostMessageW (msg->hwnd, msg->message, msg->wParam, msg->lParam);
1768 else if (msg->message == WM_CREATE)
1770 window = (UNALIGNED GdkWindow*) (((LPCREATESTRUCTW) msg->lParam)->lpCreateParams);
1771 GDK_WINDOW_HWND (window) = msg->hwnd;
1775 GDK_NOTE (EVENTS, g_print (" (no GdkWindow)"));
1780 device_manager = gdk_display_get_device_manager (_gdk_display);
1782 keyboard_grab = _gdk_display_get_last_device_grab (_gdk_display,
1783 GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
1784 pointer_grab = _gdk_display_get_last_device_grab (_gdk_display,
1785 GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_pointer);
1787 g_object_ref (window);
1789 /* window's refcount has now been increased, so code below should
1790 * not just return from this function, but instead goto done (or
1791 * break out of the big switch). To protect against forgetting this,
1792 * #define return to a syntax error...
1794 #define return GOTO_DONE_INSTEAD
1796 if (!GDK_WINDOW_DESTROYED (window) && window->filters)
1798 /* Apply per-window filters */
1800 GdkFilterReturn result = apply_event_filters (window, msg, &window->filters);
1802 if (result == GDK_FILTER_REMOVE || result == GDK_FILTER_TRANSLATE)
1809 if (msg->message == client_message)
1812 GdkFilterReturn result = GDK_FILTER_CONTINUE;
1815 GDK_NOTE (EVENTS, g_print (" client_message"));
1817 event = gdk_event_new (GDK_NOTHING);
1818 ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
1820 node = _gdk_event_queue_append (_gdk_display, event);
1822 tmp_list = client_filters;
1825 GdkClientFilter *filter = tmp_list->data;
1827 tmp_list = tmp_list->next;
1829 if (filter->type == GDK_POINTER_TO_ATOM (msg->wParam))
1831 GDK_NOTE (EVENTS, g_print (" (match)"));
1833 result = (*filter->function) (msg, event, filter->data);
1835 if (result != GDK_FILTER_CONTINUE)
1842 case GDK_FILTER_REMOVE:
1843 _gdk_event_queue_remove_link (_gdk_display, node);
1844 g_list_free_1 (node);
1845 gdk_event_free (event);
1849 case GDK_FILTER_TRANSLATE:
1850 ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1851 GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
1855 case GDK_FILTER_CONTINUE:
1856 /* No more: Send unknown client messages on to Gtk for it to use */
1857 GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
1863 switch (msg->message)
1865 case WM_INPUTLANGCHANGE:
1866 _gdk_input_locale = (HKL) msg->lParam;
1867 _gdk_input_locale_is_ime = ImmIsIME (_gdk_input_locale);
1868 GetLocaleInfo (MAKELCID (LOWORD (_gdk_input_locale), SORT_DEFAULT),
1869 LOCALE_IDEFAULTANSICODEPAGE,
1871 _gdk_input_codepage = atoi (buf);
1872 _gdk_keymap_serial++;
1874 g_print (" cs:%lu hkl:%p%s cp:%d",
1875 (gulong) msg->wParam,
1876 (gpointer) msg->lParam, _gdk_input_locale_is_ime ? " (IME)" : "",
1877 _gdk_input_codepage));
1883 g_print (" %s ch:%.02x %s",
1884 _gdk_win32_key_to_string (msg->lParam),
1886 decode_key_lparam (msg->lParam)));
1888 /* If posted without us having keyboard focus, ignore */
1889 if ((msg->wParam != VK_F10 && msg->wParam != VK_MENU) &&
1890 !(HIWORD (msg->lParam) & KF_ALTDOWN))
1893 /* Let the system handle Alt-Tab, Alt-Space and Alt-F4 unless
1894 * the keyboard is grabbed.
1896 if (!keyboard_grab &&
1897 (msg->wParam == VK_TAB ||
1898 msg->wParam == VK_SPACE ||
1899 msg->wParam == VK_F4))
1902 /* Jump to code in common with WM_KEYUP and WM_KEYDOWN */
1908 g_print (" %s ch:%.02x %s",
1909 _gdk_win32_key_to_string (msg->lParam),
1911 decode_key_lparam (msg->lParam)));
1915 /* Ignore key messages intended for the IME */
1916 if (msg->wParam == VK_PROCESSKEY ||
1920 if (keyboard_grab &&
1921 !propagate (&window, msg,
1922 keyboard_grab->window,
1923 keyboard_grab->owner_events,
1924 GDK_ALL_EVENTS_MASK,
1925 doesnt_want_key, FALSE))
1928 if (GDK_WINDOW_DESTROYED (window))
1931 event = gdk_event_new ((msg->message == WM_KEYDOWN ||
1932 msg->message == WM_SYSKEYDOWN) ?
1933 GDK_KEY_PRESS : GDK_KEY_RELEASE);
1934 event->key.window = window;
1935 event->key.time = _gdk_win32_get_next_tick (msg->time);
1936 event->key.keyval = GDK_KEY_VoidSymbol;
1937 event->key.string = NULL;
1938 event->key.length = 0;
1939 event->key.hardware_keycode = msg->wParam;
1940 gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
1941 if (HIWORD (msg->lParam) & KF_EXTENDED)
1943 switch (msg->wParam)
1946 event->key.hardware_keycode = VK_RCONTROL;
1948 case VK_SHIFT: /* Actually, KF_EXTENDED is not set
1949 * for the right shift key.
1951 event->key.hardware_keycode = VK_RSHIFT;
1954 event->key.hardware_keycode = VK_RMENU;
1958 else if (msg->wParam == VK_SHIFT &&
1959 LOBYTE (HIWORD (msg->lParam)) == _scancode_rshift)
1960 event->key.hardware_keycode = VK_RSHIFT;
1962 API_CALL (GetKeyboardState, (key_state));
1964 /* g_print ("ctrl:%02x lctrl:%02x rctrl:%02x alt:%02x lalt:%02x ralt:%02x\n", key_state[VK_CONTROL], key_state[VK_LCONTROL], key_state[VK_RCONTROL], key_state[VK_MENU], key_state[VK_LMENU], key_state[VK_RMENU]); */
1966 build_key_event_state (event, key_state);
1968 if (msg->wParam == VK_PACKET &&
1969 ToUnicode (VK_PACKET, HIWORD (msg->lParam), key_state, wbuf, 1, 0) == 1)
1970 event->key.keyval = gdk_unicode_to_keyval (wbuf[0]);
1972 gdk_keymap_translate_keyboard_state (_gdk_win32_display_get_keymap (_gdk_display),
1973 event->key.hardware_keycode,
1979 fill_key_event_string (event);
1981 /* Reset MOD1_MASK if it is the Alt key itself */
1982 if (msg->wParam == VK_MENU)
1983 event->key.state &= ~GDK_MOD1_MASK;
1985 append_event (event);
1991 if (msg->wParam != VK_SPACE)
1993 /* To prevent beeps, don't let DefWindowProcW() be called */
1999 case WM_IME_STARTCOMPOSITION:
2000 in_ime_composition = TRUE;
2003 case WM_IME_ENDCOMPOSITION:
2004 in_ime_composition = FALSE;
2007 case WM_IME_COMPOSITION:
2008 /* On Win2k WM_IME_CHAR doesn't work correctly for non-Unicode
2009 * applications. Thus, handle WM_IME_COMPOSITION with
2010 * GCS_RESULTSTR instead, fetch the Unicode chars from the IME
2011 * with ImmGetCompositionStringW().
2014 * http://groups.google.com/groups?selm=natX5.57%24g77.19788%40nntp2.onemain.com
2016 * http://groups.google.com/groups?selm=u2XfrXw5BHA.1628%40tkmsftngp02
2017 * for comments by other people that seems to have the same
2018 * experience. WM_IME_CHAR just gives question marks, apparently
2019 * because of going through some conversion to the current code
2022 * WM_IME_CHAR might work on NT4 or Win9x with ActiveIMM, but
2023 * use WM_IME_COMPOSITION there, too, to simplify the code.
2025 GDK_NOTE (EVENTS, g_print (" %#lx", (long) msg->lParam));
2027 if (!(msg->lParam & GCS_RESULTSTR))
2030 if (keyboard_grab &&
2031 !propagate (&window, msg,
2032 keyboard_grab->window,
2033 keyboard_grab->owner_events,
2034 GDK_ALL_EVENTS_MASK,
2035 doesnt_want_char, FALSE))
2038 if (GDK_WINDOW_DESTROYED (window))
2041 himc = ImmGetContext (msg->hwnd);
2042 ccount = ImmGetCompositionStringW (himc, GCS_RESULTSTR,
2043 wbuf, sizeof (wbuf));
2044 ImmReleaseContext (msg->hwnd, himc);
2048 API_CALL (GetKeyboardState, (key_state));
2050 for (i = 0; i < ccount; i++)
2052 if (window->event_mask & GDK_KEY_PRESS_MASK)
2054 /* Build a key press event */
2055 event = gdk_event_new (GDK_KEY_PRESS);
2056 event->key.window = window;
2057 gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
2058 build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
2060 append_event (event);
2063 if (window->event_mask & GDK_KEY_RELEASE_MASK)
2065 /* Build a key release event. */
2066 event = gdk_event_new (GDK_KEY_RELEASE);
2067 event->key.window = window;
2068 gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
2069 build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
2071 append_event (event);
2077 case WM_LBUTTONDOWN:
2081 case WM_MBUTTONDOWN:
2085 case WM_RBUTTONDOWN:
2089 case WM_XBUTTONDOWN:
2090 if (HIWORD (msg->wParam) == XBUTTON1)
2097 g_print (" (%d,%d)",
2098 GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
2100 assign_object (&window, find_window_for_mouse_event (window, msg));
2101 /* TODO_CSW?: there used to some synthesize and propagate */
2102 if (GDK_WINDOW_DESTROYED (window))
2105 /* TODO_CSW? Emulate X11's automatic active grab */
2106 generate_button_event (GDK_BUTTON_PRESS, button,
2125 if (HIWORD (msg->wParam) == XBUTTON1)
2132 g_print (" (%d,%d)",
2133 GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
2135 assign_object (&window, find_window_for_mouse_event (window, msg));
2137 if (window->extension_events != 0 &&
2138 _gdk_input_ignore_core)
2140 GDK_NOTE (EVENTS, g_print (" (ignored)"));
2145 generate_button_event (GDK_BUTTON_RELEASE, button,
2153 g_print (" %p (%d,%d)",
2154 (gpointer) msg->wParam,
2155 GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
2157 assign_object (&window, find_window_for_mouse_event (window, msg));
2158 toplevel = gdk_window_get_toplevel (window);
2159 if (current_toplevel != toplevel)
2161 GDK_NOTE (EVENTS, g_print (" toplevel %p -> %p",
2162 current_toplevel ? GDK_WINDOW_HWND (current_toplevel) : NULL,
2163 toplevel ? GDK_WINDOW_HWND (toplevel) : NULL));
2164 if (current_toplevel)
2165 synthesize_enter_or_leave_event (current_toplevel, msg,
2166 GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
2167 synthesize_enter_or_leave_event (toplevel, msg,
2168 GDK_ENTER_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
2169 assign_object (¤t_toplevel, toplevel);
2170 track_mouse_event (TME_LEAVE, GDK_WINDOW_HWND (toplevel));
2173 /* If we haven't moved, don't create any GDK event. Windows
2174 * sends WM_MOUSEMOVE messages after a new window is shows under
2175 * the mouse, even if the mouse hasn't moved. This disturbs gtk.
2177 if (msg->pt.x + _gdk_offset_x == current_root_x &&
2178 msg->pt.y + _gdk_offset_y == current_root_y)
2181 current_root_x = msg->pt.x + _gdk_offset_x;
2182 current_root_y = msg->pt.y + _gdk_offset_y;
2184 event = gdk_event_new (GDK_MOTION_NOTIFY);
2185 event->motion.window = window;
2186 event->motion.time = _gdk_win32_get_next_tick (msg->time);
2187 event->motion.x = current_x = (gint16) GET_X_LPARAM (msg->lParam);
2188 event->motion.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam);
2189 event->motion.x_root = current_root_x;
2190 event->motion.y_root = current_root_y;
2191 event->motion.axes = NULL;
2192 event->motion.state = build_pointer_event_state (msg);
2193 event->motion.is_hint = FALSE;
2194 gdk_event_set_device (event, _gdk_display->core_pointer);
2196 append_event (event);
2201 case WM_NCMOUSEMOVE:
2203 g_print (" (%d,%d)",
2204 GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
2208 GDK_NOTE (EVENTS, g_print (" %d (%ld,%ld)",
2209 HIWORD (msg->wParam), msg->pt.x, msg->pt.y));
2211 if (!gdk_win32_handle_table_lookup (WindowFromPoint (msg->pt)))
2213 /* we are only interested if we don't know the new window */
2214 if (current_toplevel)
2215 synthesize_enter_or_leave_event (current_toplevel, msg,
2216 GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
2217 assign_object (¤t_toplevel, NULL);
2219 else if (window != gdk_window_get_toplevel (window)) /* xxx: only for native child windows? */
2221 /* XXX: this used to be ignored pre-csw, but I think we need at least some
2222 * of the leave events */
2223 synthesize_enter_or_leave_event (window, msg,
2224 GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
2231 GDK_NOTE (EVENTS, g_print (" %d", (short) HIWORD (msg->wParam)));
2233 /* WM_MOUSEWHEEL is delivered to the focus window. Work around
2234 * that. Also, the position is in screen coordinates, not client
2235 * coordinates as with the button messages. I love the
2236 * consistency of Windows.
2238 point.x = GET_X_LPARAM (msg->lParam);
2239 point.y = GET_Y_LPARAM (msg->lParam);
2241 if ((hwnd = WindowFromPoint (point)) == NULL)
2245 if ((new_window = gdk_win32_handle_table_lookup (msg->hwnd)) == NULL)
2248 if (new_window != window)
2250 assign_object (&window, new_window);
2253 ScreenToClient (msg->hwnd, &point);
2255 event = gdk_event_new (GDK_SCROLL);
2256 event->scroll.window = window;
2257 event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
2258 GDK_SCROLL_UP : GDK_SCROLL_DOWN;
2259 event->scroll.time = _gdk_win32_get_next_tick (msg->time);
2260 event->scroll.x = (gint16) point.x;
2261 event->scroll.y = (gint16) point.y;
2262 event->scroll.x_root = (gint16) GET_X_LPARAM (msg->lParam) + _gdk_offset_x;
2263 event->scroll.y_root = (gint16) GET_Y_LPARAM (msg->lParam) + _gdk_offset_y;
2264 event->scroll.state = build_pointer_event_state (msg);
2265 gdk_event_set_device (event, _gdk_display->core_pointer);
2267 append_event (event);
2273 /* Just print more debugging information, don't actually handle it. */
2276 (LOWORD (msg->wParam) == SB_ENDSCROLL ? "ENDSCROLL" :
2277 (LOWORD (msg->wParam) == SB_LEFT ? "LEFT" :
2278 (LOWORD (msg->wParam) == SB_RIGHT ? "RIGHT" :
2279 (LOWORD (msg->wParam) == SB_LINELEFT ? "LINELEFT" :
2280 (LOWORD (msg->wParam) == SB_LINERIGHT ? "LINERIGHT" :
2281 (LOWORD (msg->wParam) == SB_PAGELEFT ? "PAGELEFT" :
2282 (LOWORD (msg->wParam) == SB_PAGERIGHT ? "PAGERIGHT" :
2283 (LOWORD (msg->wParam) == SB_THUMBPOSITION ? "THUMBPOSITION" :
2284 (LOWORD (msg->wParam) == SB_THUMBTRACK ? "THUMBTRACK" :
2286 (LOWORD (msg->wParam) == SB_THUMBPOSITION ||
2287 LOWORD (msg->wParam) == SB_THUMBTRACK) ?
2288 (g_print (" %d", HIWORD (msg->wParam)), 0) : 0));
2292 /* Just print more debugging information, don't actually handle it. */
2295 (LOWORD (msg->wParam) == SB_ENDSCROLL ? "ENDSCROLL" :
2296 (LOWORD (msg->wParam) == SB_BOTTOM ? "BOTTOM" :
2297 (LOWORD (msg->wParam) == SB_TOP ? "TOP" :
2298 (LOWORD (msg->wParam) == SB_LINEDOWN ? "LINDOWN" :
2299 (LOWORD (msg->wParam) == SB_LINEUP ? "LINEUP" :
2300 (LOWORD (msg->wParam) == SB_PAGEDOWN ? "PAGEDOWN" :
2301 (LOWORD (msg->wParam) == SB_PAGEUP ? "PAGEUP" :
2302 (LOWORD (msg->wParam) == SB_THUMBPOSITION ? "THUMBPOSITION" :
2303 (LOWORD (msg->wParam) == SB_THUMBTRACK ? "THUMBTRACK" :
2305 (LOWORD (msg->wParam) == SB_THUMBPOSITION ||
2306 LOWORD (msg->wParam) == SB_THUMBTRACK) ?
2307 (g_print (" %d", HIWORD (msg->wParam)), 0) : 0));
2310 case WM_MOUSEACTIVATE:
2314 if (gdk_window_get_window_type (window) == GDK_WINDOW_TEMP
2315 || !window->accept_focus)
2317 *ret_valp = MA_NOACTIVATE;
2321 tmp = _gdk_modal_current ();
2325 if (gdk_window_get_toplevel (window) != tmp)
2327 *ret_valp = MA_NOACTIVATEANDEAT;
2336 if (keyboard_grab != NULL &&
2337 !GDK_WINDOW_DESTROYED (keyboard_grab->window))
2339 generate_grab_broken_event (device_manager, keyboard_grab->window, TRUE, NULL);
2344 if (keyboard_grab != NULL &&
2345 !keyboard_grab->owner_events)
2348 if (!(window->event_mask & GDK_FOCUS_CHANGE_MASK))
2351 if (GDK_WINDOW_DESTROYED (window))
2354 generate_focus_event (device_manager, window, (msg->message == WM_SETFOCUS));
2359 GDK_NOTE (EVENTS, g_print (" %p", (HANDLE) msg->wParam));
2361 if (GDK_WINDOW_DESTROYED (window))
2369 sync_timer = SetTimer (GDK_WINDOW_HWND (window),
2371 200, sync_timer_proc);
2375 handle_wm_paint (msg, window, FALSE, NULL);
2379 GDK_NOTE (EVENTS, g_print (" %#x %#x",
2380 LOWORD (msg->lParam), HIWORD (msg->lParam)));
2382 if (pointer_grab != NULL)
2383 grab_window = pointer_grab->window;
2385 if (grab_window == NULL && LOWORD (msg->lParam) != HTCLIENT)
2388 if (grab_window != NULL && p_grab_cursor != NULL)
2389 hcursor = p_grab_cursor;
2390 else if (!GDK_WINDOW_DESTROYED (window))
2391 hcursor = GDK_WINDOW_IMPL_WIN32 (window->impl)->hcursor;
2395 if (hcursor != NULL)
2397 GDK_NOTE (EVENTS, g_print (" (SetCursor(%p)", hcursor));
2398 SetCursor (hcursor);
2405 GDK_NOTE (EVENTS, g_print (" %s %s",
2406 (msg->wParam ? "YES" : "NO"),
2407 (msg->lParam == 0 ? "ShowWindow" :
2408 (msg->lParam == SW_OTHERUNZOOM ? "OTHERUNZOOM" :
2409 (msg->lParam == SW_OTHERZOOM ? "OTHERZOOM" :
2410 (msg->lParam == SW_PARENTCLOSING ? "PARENTCLOSING" :
2411 (msg->lParam == SW_PARENTOPENING ? "PARENTOPENING" :
2414 if (!(window->event_mask & GDK_STRUCTURE_MASK))
2417 if (msg->lParam == SW_OTHERUNZOOM ||
2418 msg->lParam == SW_OTHERZOOM)
2421 if (GDK_WINDOW_DESTROYED (window))
2424 event = gdk_event_new (msg->wParam ? GDK_MAP : GDK_UNMAP);
2425 event->any.window = window;
2427 append_event (event);
2429 if (event->any.type == GDK_UNMAP)
2431 impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2433 if (impl->transient_owner && GetForegroundWindow () == GDK_WINDOW_HWND (window))
2435 SetForegroundWindow (GDK_WINDOW_HWND (impl->transient_owner));
2438 if (pointer_grab != NULL)
2440 if (pointer_grab->window == window)
2441 gdk_pointer_ungrab (msg->time);
2444 if (keyboard_grab &&
2445 keyboard_grab->window == window)
2446 gdk_keyboard_ungrab (msg->time);
2453 switch (msg->wParam)
2457 do_show_window (window, msg->wParam == SC_MINIMIZE ? TRUE : FALSE);
2465 g_print (" %s %dx%d",
2466 (msg->wParam == SIZE_MAXHIDE ? "MAXHIDE" :
2467 (msg->wParam == SIZE_MAXIMIZED ? "MAXIMIZED" :
2468 (msg->wParam == SIZE_MAXSHOW ? "MAXSHOW" :
2469 (msg->wParam == SIZE_MINIMIZED ? "MINIMIZED" :
2470 (msg->wParam == SIZE_RESTORED ? "RESTORED" : "?"))))),
2471 LOWORD (msg->lParam), HIWORD (msg->lParam)));
2473 if (msg->wParam == SIZE_MINIMIZED)
2475 /* Don't generate any GDK event. This is *not* an UNMAP. */
2476 if (pointer_grab != NULL)
2478 if (pointer_grab->window == window)
2479 gdk_pointer_ungrab (msg->time);
2481 if (keyboard_grab &&
2482 keyboard_grab->window == window)
2483 gdk_keyboard_ungrab (msg->time);
2485 gdk_synthesize_window_state (window,
2486 GDK_WINDOW_STATE_WITHDRAWN,
2487 GDK_WINDOW_STATE_ICONIFIED);
2488 do_show_window (window, TRUE);
2490 else if ((msg->wParam == SIZE_RESTORED ||
2491 msg->wParam == SIZE_MAXIMIZED) &&
2492 GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
2494 GdkWindowState withdrawn_bit =
2495 IsWindowVisible (msg->hwnd) ? GDK_WINDOW_STATE_WITHDRAWN : 0;
2497 if (window->state & GDK_WINDOW_STATE_ICONIFIED)
2498 ensure_stacking_on_unminimize (msg);
2500 if (!GDK_WINDOW_DESTROYED (window))
2501 handle_configure_event (msg, window);
2503 if (msg->wParam == SIZE_RESTORED)
2505 gdk_synthesize_window_state (window,
2506 GDK_WINDOW_STATE_ICONIFIED |
2507 GDK_WINDOW_STATE_MAXIMIZED |
2511 if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_TEMP && !GDK_WINDOW_IS_MAPPED (window))
2513 do_show_window (window, FALSE);
2516 else if (msg->wParam == SIZE_MAXIMIZED)
2518 gdk_synthesize_window_state (window,
2519 GDK_WINDOW_STATE_ICONIFIED |
2521 GDK_WINDOW_STATE_MAXIMIZED);
2524 if (window->resize_count > 1)
2525 window->resize_count -= 1;
2527 if (window->extension_events != 0)
2528 _gdk_device_wintab_update_window_coords (window);
2534 case WM_ENTERSIZEMOVE:
2535 case WM_ENTERMENULOOP:
2536 _gdk_win32_begin_modal_call ();
2539 case WM_EXITSIZEMOVE:
2540 case WM_EXITMENULOOP:
2541 _gdk_win32_end_modal_call ();
2544 case WM_WINDOWPOSCHANGING:
2545 GDK_NOTE (EVENTS, (windowpos = (WINDOWPOS *) msg->lParam,
2546 g_print (" %s %s %dx%d@%+d%+d now below %p",
2547 _gdk_win32_window_pos_bits_to_string (windowpos->flags),
2548 (windowpos->hwndInsertAfter == HWND_BOTTOM ? "BOTTOM" :
2549 (windowpos->hwndInsertAfter == HWND_NOTOPMOST ? "NOTOPMOST" :
2550 (windowpos->hwndInsertAfter == HWND_TOP ? "TOP" :
2551 (windowpos->hwndInsertAfter == HWND_TOPMOST ? "TOPMOST" :
2552 (sprintf (buf, "%p", windowpos->hwndInsertAfter),
2554 windowpos->cx, windowpos->cy, windowpos->x, windowpos->y,
2555 GetNextWindow (msg->hwnd, GW_HWNDPREV))));
2557 if (GDK_WINDOW_IS_MAPPED (window))
2558 return_val = ensure_stacking_on_window_pos_changing (msg, window);
2561 case WM_WINDOWPOSCHANGED:
2562 windowpos = (WINDOWPOS *) msg->lParam;
2563 GDK_NOTE (EVENTS, g_print (" %s %s %dx%d@%+d%+d",
2564 _gdk_win32_window_pos_bits_to_string (windowpos->flags),
2565 (windowpos->hwndInsertAfter == HWND_BOTTOM ? "BOTTOM" :
2566 (windowpos->hwndInsertAfter == HWND_NOTOPMOST ? "NOTOPMOST" :
2567 (windowpos->hwndInsertAfter == HWND_TOP ? "TOP" :
2568 (windowpos->hwndInsertAfter == HWND_TOPMOST ? "TOPMOST" :
2569 (sprintf (buf, "%p", windowpos->hwndInsertAfter),
2571 windowpos->cx, windowpos->cy, windowpos->x, windowpos->y));
2573 /* If position and size haven't changed, don't do anything */
2574 if (_modal_operation_in_progress &&
2575 (windowpos->flags & SWP_NOMOVE) &&
2576 (windowpos->flags & SWP_NOSIZE))
2579 /* Once we've entered the moving or sizing modal loop, we won't
2580 * return to the main loop until we're done sizing or moving.
2582 if (_modal_operation_in_progress &&
2583 GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
2584 !GDK_WINDOW_DESTROYED (window))
2586 if (window->event_mask & GDK_STRUCTURE_MASK)
2588 GDK_NOTE (EVENTS, g_print (" do magic"));
2589 if (window->resize_count > 1)
2590 window->resize_count -= 1;
2592 handle_configure_event (msg, window);
2593 g_main_context_iteration (NULL, FALSE);
2595 /* Dispatch main loop - to realize resizes... */
2596 modal_timer_proc (msg->hwnd, msg->message, 0, msg->time);
2598 /* Claim as handled, so that WM_SIZE and WM_MOVE are avoided */
2606 GetWindowRect (GDK_WINDOW_HWND (window), &rect);
2607 drag = (RECT *) msg->lParam;
2608 GDK_NOTE (EVENTS, g_print (" %s curr:%s drag:%s",
2609 (msg->wParam == WMSZ_BOTTOM ? "BOTTOM" :
2610 (msg->wParam == WMSZ_BOTTOMLEFT ? "BOTTOMLEFT" :
2611 (msg->wParam == WMSZ_LEFT ? "LEFT" :
2612 (msg->wParam == WMSZ_TOPLEFT ? "TOPLEFT" :
2613 (msg->wParam == WMSZ_TOP ? "TOP" :
2614 (msg->wParam == WMSZ_TOPRIGHT ? "TOPRIGHT" :
2615 (msg->wParam == WMSZ_RIGHT ? "RIGHT" :
2617 (msg->wParam == WMSZ_BOTTOMRIGHT ? "BOTTOMRIGHT" :
2619 _gdk_win32_rect_to_string (&rect),
2620 _gdk_win32_rect_to_string (drag)));
2622 impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2624 if (impl->hint_flags & GDK_HINT_RESIZE_INC)
2626 GDK_NOTE (EVENTS, g_print (" (RESIZE_INC)"));
2627 if (impl->hint_flags & GDK_HINT_BASE_SIZE)
2629 /* Resize in increments relative to the base size */
2630 rect.left = rect.top = 0;
2631 rect.right = impl->hints.base_width;
2632 rect.bottom = impl->hints.base_height;
2633 _gdk_win32_adjust_client_rect (window, &rect);
2634 point.x = rect.left;
2636 ClientToScreen (GDK_WINDOW_HWND (window), &point);
2637 rect.left = point.x;
2639 point.x = rect.right;
2640 point.y = rect.bottom;
2641 ClientToScreen (GDK_WINDOW_HWND (window), &point);
2642 rect.right = point.x;
2643 rect.bottom = point.y;
2645 GDK_NOTE (EVENTS, g_print (" (also BASE_SIZE, using %s)",
2646 _gdk_win32_rect_to_string (&rect)));
2649 switch (msg->wParam)
2652 if (drag->bottom == rect.bottom)
2654 adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
2657 case WMSZ_BOTTOMLEFT:
2658 if (drag->bottom == rect.bottom && drag->left == rect.left)
2660 adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
2661 adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
2665 if (drag->left == rect.left)
2667 adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
2671 if (drag->top == rect.top && drag->left == rect.left)
2673 adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
2674 adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
2678 if (drag->top == rect.top)
2680 adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
2684 if (drag->top == rect.top && drag->right == rect.right)
2686 adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
2687 adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
2691 if (drag->right == rect.right)
2693 adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
2696 case WMSZ_BOTTOMRIGHT:
2697 if (drag->bottom == rect.bottom && drag->right == rect.right)
2699 adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
2700 adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
2704 if (drag->bottom != orig_drag.bottom || drag->left != orig_drag.left ||
2705 drag->top != orig_drag.top || drag->right != orig_drag.right)
2709 GDK_NOTE (EVENTS, g_print (" (handled RESIZE_INC: %s)",
2710 _gdk_win32_rect_to_string (drag)));
2714 /* WM_GETMINMAXINFO handles min_size and max_size hints? */
2716 if (impl->hint_flags & GDK_HINT_ASPECT)
2718 RECT decorated_rect;
2719 RECT undecorated_drag;
2720 int decoration_width, decoration_height;
2721 gdouble drag_aspect;
2722 int drag_width, drag_height, new_width, new_height;
2724 GetClientRect (GDK_WINDOW_HWND (window), &rect);
2725 decorated_rect = rect;
2726 _gdk_win32_adjust_client_rect (window, &decorated_rect);
2728 /* Set undecorated_drag to the client area being dragged
2729 * out, in screen coordinates.
2731 undecorated_drag = *drag;
2732 undecorated_drag.left -= decorated_rect.left - rect.left;
2733 undecorated_drag.right -= decorated_rect.right - rect.right;
2734 undecorated_drag.top -= decorated_rect.top - rect.top;
2735 undecorated_drag.bottom -= decorated_rect.bottom - rect.bottom;
2737 decoration_width = (decorated_rect.right - decorated_rect.left) - (rect.right - rect.left);
2738 decoration_height = (decorated_rect.bottom - decorated_rect.top) - (rect.bottom - rect.top);
2740 drag_width = undecorated_drag.right - undecorated_drag.left;
2741 drag_height = undecorated_drag.bottom - undecorated_drag.top;
2743 drag_aspect = (gdouble) drag_width / drag_height;
2745 GDK_NOTE (EVENTS, g_print (" (ASPECT:%g--%g curr: %g)",
2746 impl->hints.min_aspect, impl->hints.max_aspect, drag_aspect));
2748 if (drag_aspect < impl->hints.min_aspect)
2750 /* Aspect is getting too narrow */
2751 switch (msg->wParam)
2755 /* User drags top or bottom edge outward. Keep height, increase width. */
2756 new_width = impl->hints.min_aspect * drag_height;
2757 drag->left -= (new_width - drag_width) / 2;
2758 drag->right = drag->left + new_width + decoration_width;
2760 case WMSZ_BOTTOMLEFT:
2761 case WMSZ_BOTTOMRIGHT:
2762 /* User drags bottom-left or bottom-right corner down. Adjust height. */
2763 new_height = drag_width / impl->hints.min_aspect;
2764 drag->bottom = drag->top + new_height + decoration_height;
2768 /* User drags left or right edge inward. Decrease height */
2769 new_height = drag_width / impl->hints.min_aspect;
2770 drag->top += (drag_height - new_height) / 2;
2771 drag->bottom = drag->top + new_height + decoration_height;
2775 /* User drags top-left or top-right corner up. Adjust height. */
2776 new_height = drag_width / impl->hints.min_aspect;
2777 drag->top = drag->bottom - new_height - decoration_height;
2780 else if (drag_aspect > impl->hints.max_aspect)
2782 /* Aspect is getting too wide */
2783 switch (msg->wParam)
2787 /* User drags top or bottom edge inward. Decrease width. */
2788 new_width = impl->hints.max_aspect * drag_height;
2789 drag->left += (drag_width - new_width) / 2;
2790 drag->right = drag->left + new_width + decoration_width;
2792 case WMSZ_BOTTOMLEFT:
2794 /* User drags bottom-left or top-left corner left. Adjust width. */
2795 new_width = impl->hints.max_aspect * drag_height;
2796 drag->left = drag->right - new_width - decoration_width;
2798 case WMSZ_BOTTOMRIGHT:
2800 /* User drags bottom-right or top-right corner right. Adjust width. */
2801 new_width = impl->hints.max_aspect * drag_height;
2802 drag->right = drag->left + new_width + decoration_width;
2806 /* User drags left or right edge outward. Increase height. */
2807 new_height = drag_width / impl->hints.max_aspect;
2808 drag->top -= (new_height - drag_height) / 2;
2809 drag->bottom = drag->top + new_height + decoration_height;
2816 GDK_NOTE (EVENTS, g_print (" (handled ASPECT: %s)",
2817 _gdk_win32_rect_to_string (drag)));
2821 case WM_GETMINMAXINFO:
2822 if (GDK_WINDOW_DESTROYED (window))
2825 impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2826 mmi = (MINMAXINFO*) msg->lParam;
2827 GDK_NOTE (EVENTS, g_print (" (mintrack:%ldx%ld maxtrack:%ldx%ld "
2828 "maxpos:%+ld%+ld maxsize:%ldx%ld)",
2829 mmi->ptMinTrackSize.x, mmi->ptMinTrackSize.y,
2830 mmi->ptMaxTrackSize.x, mmi->ptMaxTrackSize.y,
2831 mmi->ptMaxPosition.x, mmi->ptMaxPosition.y,
2832 mmi->ptMaxSize.x, mmi->ptMaxSize.y));
2834 if (impl->hint_flags & GDK_HINT_MIN_SIZE)
2836 rect.left = rect.top = 0;
2837 rect.right = impl->hints.min_width;
2838 rect.bottom = impl->hints.min_height;
2840 _gdk_win32_adjust_client_rect (window, &rect);
2842 mmi->ptMinTrackSize.x = rect.right - rect.left;
2843 mmi->ptMinTrackSize.y = rect.bottom - rect.top;
2846 if (impl->hint_flags & GDK_HINT_MAX_SIZE)
2850 rect.left = rect.top = 0;
2851 rect.right = impl->hints.max_width;
2852 rect.bottom = impl->hints.max_height;
2854 _gdk_win32_adjust_client_rect (window, &rect);
2856 /* at least on win9x we have the 16 bit trouble */
2857 maxw = rect.right - rect.left;
2858 maxh = rect.bottom - rect.top;
2859 mmi->ptMaxTrackSize.x = maxw > 0 && maxw < G_MAXSHORT ? maxw : G_MAXSHORT;
2860 mmi->ptMaxTrackSize.y = maxh > 0 && maxh < G_MAXSHORT ? maxh : G_MAXSHORT;
2863 if (impl->hint_flags & (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE))
2865 /* Don't call DefWindowProcW() */
2866 GDK_NOTE (EVENTS, g_print (" (handled, mintrack:%ldx%ld maxtrack:%ldx%ld "
2867 "maxpos:%+ld%+ld maxsize:%ldx%ld)",
2868 mmi->ptMinTrackSize.x, mmi->ptMinTrackSize.y,
2869 mmi->ptMaxTrackSize.x, mmi->ptMaxTrackSize.y,
2870 mmi->ptMaxPosition.x, mmi->ptMaxPosition.y,
2871 mmi->ptMaxSize.x, mmi->ptMaxSize.y));
2877 GDK_NOTE (EVENTS, g_print (" (%d,%d)",
2878 GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
2880 if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
2881 !IsIconic (msg->hwnd))
2883 if (!GDK_WINDOW_DESTROYED (window))
2884 handle_configure_event (msg, window);
2891 if (GDK_WINDOW_DESTROYED (window))
2894 event = gdk_event_new (GDK_DELETE);
2895 event->any.window = window;
2897 append_event (event);
2899 impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2901 if (impl->transient_owner && GetForegroundWindow() == GDK_WINDOW_HWND (window))
2903 SetForegroundWindow (GDK_WINDOW_HWND (impl->transient_owner));
2910 if (pointer_grab != NULL)
2912 if (pointer_grab->window == window)
2913 gdk_pointer_ungrab (msg->time);
2916 if (keyboard_grab &&
2917 keyboard_grab->window == window)
2918 gdk_keyboard_ungrab (msg->time);
2920 if ((window != NULL) && (msg->hwnd != GetDesktopWindow ()))
2921 gdk_window_destroy_notify (window);
2923 if (window == NULL || GDK_WINDOW_DESTROYED (window))
2926 event = gdk_event_new (GDK_DESTROY);
2927 event->any.window = window;
2929 append_event (event);
2934 case WM_DISPLAYCHANGE:
2935 handle_display_change ();
2938 case WM_DESTROYCLIPBOARD:
2939 if (!_ignore_destroy_clipboard)
2941 event = gdk_event_new (GDK_SELECTION_CLEAR);
2942 event->selection.window = window;
2943 event->selection.selection = GDK_SELECTION_CLIPBOARD;
2944 event->selection.time = _gdk_win32_get_next_tick (msg->time);
2945 append_event (event);
2954 case WM_RENDERFORMAT:
2955 GDK_NOTE (EVENTS, g_print (" %s", _gdk_win32_cf_to_string (msg->wParam)));
2957 if (!(target = g_hash_table_lookup (_format_atom_table, GINT_TO_POINTER (msg->wParam))))
2959 GDK_NOTE (EVENTS, g_print (" (target not found)"));
2964 /* We need to render to clipboard immediately, don't call
2967 event = gdk_event_new (GDK_SELECTION_REQUEST);
2968 event->selection.window = window;
2969 event->selection.send_event = FALSE;
2970 event->selection.selection = GDK_SELECTION_CLIPBOARD;
2971 event->selection.target = target;
2972 event->selection.property = _gdk_selection;
2973 event->selection.requestor = gdk_win32_handle_table_lookup (msg->hwnd);
2974 event->selection.time = msg->time;
2976 fixup_event (event);
2977 GDK_NOTE (EVENTS, g_print (" (calling _gdk_event_emit)"));
2978 GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
2979 _gdk_event_emit (event);
2980 gdk_event_free (event);
2982 /* Now the clipboard owner should have rendered */
2983 if (!_delayed_rendering_data)
2985 GDK_NOTE (EVENTS, g_print (" (no _delayed_rendering_data?)"));
2989 if (msg->wParam == CF_DIB)
2991 _delayed_rendering_data =
2992 _gdk_win32_selection_convert_to_dib (_delayed_rendering_data,
2994 if (!_delayed_rendering_data)
2996 g_warning ("Cannot convert to DIB from delayed rendered image");
3001 /* The requestor is holding the clipboard, no
3002 * OpenClipboard() is required/possible
3005 g_print (" SetClipboardData(%s,%p)",
3006 _gdk_win32_cf_to_string (msg->wParam),
3007 _delayed_rendering_data));
3009 API_CALL (SetClipboardData, (msg->wParam, _delayed_rendering_data));
3010 _delayed_rendering_data = NULL;
3015 GDK_NOTE (EVENTS, g_print (" %s%s %p",
3016 (LOWORD (msg->wParam) == WA_ACTIVE ? "ACTIVE" :
3017 (LOWORD (msg->wParam) == WA_CLICKACTIVE ? "CLICKACTIVE" :
3018 (LOWORD (msg->wParam) == WA_INACTIVE ? "INACTIVE" : "???"))),
3019 HIWORD (msg->wParam) ? " minimized" : "",
3020 (HWND) msg->lParam));
3021 /* We handle mouse clicks for modally-blocked windows under WM_MOUSEACTIVATE,
3022 * but we still need to deal with alt-tab, or with SetActiveWindow() type
3025 if (is_modally_blocked (window) && LOWORD (msg->wParam) == WA_ACTIVE)
3027 GdkWindow *modal_current = _gdk_modal_current ();
3028 SetActiveWindow (GDK_WINDOW_HWND (modal_current));
3034 /* Bring any tablet contexts to the top of the overlap order when
3035 * one of our windows is activated.
3036 * NOTE: It doesn't seem to work well if it is done in WM_ACTIVATEAPP
3039 if (LOWORD(msg->wParam) != WA_INACTIVE)
3040 _gdk_input_set_tablet_active ();
3043 case WM_ACTIVATEAPP:
3044 GDK_NOTE (EVENTS, g_print (" %s thread: %I64d",
3045 msg->wParam ? "YES" : "NO",
3046 (gint64) msg->lParam));
3047 if (msg->wParam && GDK_WINDOW_IS_MAPPED (window))
3048 ensure_stacking_on_activate_app (msg, window);
3051 /* Handle WINTAB events here, as we know that gdkinput.c will
3052 * use the fixed WT_DEFBASE as lcMsgBase, and we thus can use the
3053 * constants as case labels.
3056 GDK_NOTE (EVENTS, g_print (" %d %p",
3057 (int) msg->wParam, (gpointer) msg->lParam));
3061 GDK_NOTE (EVENTS, g_print (" %d %p",
3062 (int) msg->wParam, (gpointer) msg->lParam));
3066 GDK_NOTE (EVENTS, g_print (" %p %d %d",
3067 (gpointer) msg->wParam,
3068 LOWORD (msg->lParam),
3069 HIWORD (msg->lParam)));
3073 event = gdk_event_new (GDK_NOTHING);
3074 event->any.window = window;
3075 g_object_ref (window);
3077 if (_gdk_input_other_event (event, msg, window))
3078 append_event (event);
3080 gdk_event_free (event);
3088 g_object_unref (window);
3095 _gdk_win32_display_queue_events (GdkDisplay *display)
3099 if (modal_win32_dialog != NULL)
3102 while (!_gdk_event_queue_find_first (display) &&
3103 PeekMessageW (&msg, NULL, 0, 0, PM_REMOVE))
3105 TranslateMessage (&msg);
3106 DispatchMessageW (&msg);
3111 gdk_event_prepare (GSource *source,
3117 GDK_THREADS_ENTER ();
3121 retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
3122 (modal_win32_dialog == NULL &&
3123 PeekMessageW (&msg, NULL, 0, 0, PM_NOREMOVE)));
3125 GDK_THREADS_LEAVE ();
3131 gdk_event_check (GSource *source)
3136 GDK_THREADS_ENTER ();
3138 if (event_poll_fd.revents & G_IO_IN)
3140 retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
3141 (modal_win32_dialog == NULL &&
3142 PeekMessageW (&msg, NULL, 0, 0, PM_NOREMOVE)));
3149 GDK_THREADS_LEAVE ();
3155 gdk_event_dispatch (GSource *source,
3156 GSourceFunc callback,
3161 GDK_THREADS_ENTER ();
3163 _gdk_win32_display_queue_events (_gdk_display);
3164 event = _gdk_event_unqueue (_gdk_display);
3168 _gdk_event_emit (event);
3170 gdk_event_free (event);
3172 /* Do drag & drop if it is still pending */
3173 if (_dnd_source_state == GDK_WIN32_DND_PENDING)
3175 _dnd_source_state = GDK_WIN32_DND_DRAGGING;
3176 _gdk_win32_dnd_do_dragdrop ();
3177 _dnd_source_state = GDK_WIN32_DND_NONE;
3181 GDK_THREADS_LEAVE ();
3187 gdk_win32_set_modal_dialog_libgtk_only (HWND window)
3189 modal_win32_dialog = window;
3193 is_modally_blocked (GdkWindow *window)
3195 GdkWindow *modal_current = _gdk_modal_current ();
3196 return modal_current != NULL ? gdk_window_get_toplevel (window) != modal_current : FALSE;
3200 _gdk_win32_display_sync (GdkDisplay * display)
3204 g_return_if_fail (display == _gdk_display);
3206 /* Process all messages currently available */
3207 while (PeekMessageW (&msg, NULL, 0, 0, PM_REMOVE))
3208 DispatchMessageW (&msg);