1 /* Cockos SWELL (Simple/Small Win32 Emulation Layer for Linux/OSX)
2 Copyright (C) 2006 and later, Cockos, Inc.
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
24 #ifndef SWELL_PROVIDED_BY_APP
30 #define STR2(x) STR(x)
32 char __attribute__ ((visibility ("default"))) SWELL_WANT_LOAD_LIBRARY
[] = STR2(SWELL_PRELOAD
);
38 #ifdef SWELL_TARGET_GDK
40 #include "swell-internal.h"
41 #include "swell-dlggen.h"
42 #include "../wdlcstring.h"
43 #include "../wdlutf8.h"
46 #if !defined(SWELL_TARGET_GDK_NO_CURSOR_HACK)
47 #define SWELL_TARGET_GDK_CURSORHACK
48 #include <X11/extensions/XInput2.h>
51 #include <X11/Xatom.h>
53 static void (*_gdk_drag_drop_done
)(GdkDragContext
*, gboolean
); // may not always be available
55 static guint32
_gdk_x11_window_get_desktop(GdkWindow
*window
)
59 gulong nitems
=0, bytes_after
;
62 if (!window
|| !gdk_x11_screen_supports_net_wm_hint(gdk_window_get_screen(window
),
63 gdk_atom_intern_static_string("_NET_WM_DESKTOP")))
66 XGetWindowProperty(GDK_WINDOW_XDISPLAY(window
), GDK_WINDOW_XID(window
),
67 gdk_x11_get_xatom_by_name_for_display(gdk_window_get_display(window
), "_NET_WM_DESKTOP"),
68 0, G_MAXLONG
, false, XA_CARDINAL
, &type
, &format
, &nitems
, &bytes_after
, &data
);
69 if (type
!= XA_CARDINAL
|| nitems
<1) return 0;
70 nitems
= *(gulong
*)data
;
72 return (guint32
) nitems
;
75 static void _gdk_x11_window_move_to_desktop(GdkWindow
*window
, guint32 desktop
)
77 XClientMessageEvent xclient
;
79 if (!window
|| !gdk_x11_screen_supports_net_wm_hint(gdk_window_get_screen(window
),
80 gdk_atom_intern_static_string("_NET_WM_DESKTOP")))
83 memset (&xclient
, 0, sizeof (xclient
));
84 xclient
.type
= ClientMessage
;
85 xclient
.send_event
= true;
86 xclient
.window
= GDK_WINDOW_XID(window
);
87 xclient
.message_type
= gdk_x11_get_xatom_by_name_for_display(gdk_window_get_display(window
), "_NET_WM_DESKTOP");
89 xclient
.data
.l
[0] = desktop
;
90 xclient
.data
.l
[1] = 1;
92 XSendEvent(GDK_WINDOW_XDISPLAY(window
), gdk_x11_get_default_root_xwindow(), false,
93 SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xclient
);
96 // for m_oswindow_private
97 #define PRIVATE_NEEDSHOW 1
99 #ifndef SWELL_WINDOWSKEY_GDK_MASK
100 #define SWELL_WINDOWSKEY_GDK_MASK GDK_MOD4_MASK
103 static int SWELL_gdk_active
;
104 static GdkEvent
*s_cur_evt
;
105 static GList
*s_program_icon_list
;
107 static SWELL_OSWINDOW swell_dragsrc_osw
;
108 static DWORD swell_dragsrc_timeout
;
109 static HWND swell_dragsrc_hwnd
;
110 static DWORD swell_lastMessagePos
;
111 static int gdk_options
;
112 #define OPTION_KEEP_OWNED_ABOVE 1
113 #define OPTION_OWNED_TASKLIST 2
114 #define OPTION_BORDERLESS_OVERRIDEREDIRECT 4
116 static HWND s_ddrop_hwnd
;
117 static POINT s_ddrop_pt
;
119 static SWELL_CursorResourceIndex
*SWELL_curmodule_cursorresource_head
;
121 static int s_cursor_vis_cnt
;
123 static HCURSOR s_last_cursor
;
124 static HCURSOR s_last_setcursor
;
125 static SWELL_OSWINDOW s_last_setcursor_oswnd
;
127 static void *g_swell_touchptr
; // last GDK touch sequence
128 static void *g_swell_touchptr_wnd
; // last window of touch sequence, for forcing end of sequence on destroy
130 static bool g_swell_mouse_relmode
;
131 static int g_swell_mouse_relmode_curpos_x
;
132 static int g_swell_mouse_relmode_curpos_y
;
134 static HANDLE s_clipboard_getstate
, s_clipboard_setstate
;
135 static GdkAtom s_clipboard_getstate_fmt
, s_clipboard_setstate_fmt
;
137 static WDL_IntKeyedArray
<HANDLE
> m_clip_recs(GlobalFree
);
138 static WDL_PtrList
<char> m_clip_curfmts
;
139 static HWND s_clip_hwnd
;
141 static void swell_gdkEventHandler(GdkEvent
*event
, gpointer data
);
143 static int s_last_desktop
;
144 static UINT_PTR s_deactivate_timer
;
145 static guint32 s_force_window_time
;
147 static void on_activate(guint32 ftime
)
149 s_force_window_time
= ftime
;
150 swell_app_is_inactive
=false;
151 HWND h
= SWELL_topwindows
;
157 gdk_window_set_keep_above(h
->m_oswindow
,TRUE
);
160 gdk_window_set_accept_focus(h
->m_oswindow
,FALSE
);
163 PostMessage(h
,WM_ACTIVATEAPP
,1,0);
167 s_force_window_time
= 0;
170 static void on_deactivate()
172 swell_app_is_inactive
=true;
173 HWND lf
= swell_oswindow_to_hwnd(SWELL_focused_oswindow
);
174 s_last_desktop
= lf
&& lf
->m_oswindow
? _gdk_x11_window_get_desktop(lf
->m_oswindow
)+1 : 0;
176 HWND h
= SWELL_topwindows
;
182 gdk_window_set_keep_above(h
->m_oswindow
,FALSE
);
184 gdk_window_set_accept_focus(h
->m_oswindow
,TRUE
); // allow the user to activate app by clicking
186 PostMessage(h
,WM_ACTIVATEAPP
,0,0);
192 void swell_oswindow_destroy(HWND hwnd
)
194 if (hwnd
&& hwnd
->m_oswindow
)
196 if (SWELL_focused_oswindow
== hwnd
->m_oswindow
) SWELL_focused_oswindow
= NULL
;
197 if (g_swell_touchptr
&& g_swell_touchptr_wnd
== hwnd
->m_oswindow
)
198 g_swell_touchptr
= NULL
;
199 gdk_window_destroy(hwnd
->m_oswindow
);
200 hwnd
->m_oswindow
=NULL
;
201 #ifdef SWELL_LICE_GDI
202 delete hwnd
->m_backingstore
;
203 hwnd
->m_backingstore
=0;
206 if (swell_app_is_inactive
)
208 HWND h
= SWELL_topwindows
;
211 if (h
->m_oswindow
) break;
214 if (!h
) on_activate(10); // arbitrary old timestamp that is nonzero
218 void swell_oswindow_update_text(HWND hwnd
)
220 if (hwnd
&& hwnd
->m_oswindow
)
222 gdk_window_set_title(hwnd
->m_oswindow
, (char*)hwnd
->m_title
.Get());
226 void swell_oswindow_focus(HWND hwnd
)
230 SWELL_focused_oswindow
= NULL
;
234 while (hwnd
&& !hwnd
->m_oswindow
) hwnd
=hwnd
->m_parent
;
235 if (hwnd
&& !swell_app_is_inactive
)
237 gdk_window_raise(hwnd
->m_oswindow
);
238 if (hwnd
->m_oswindow
!= SWELL_focused_oswindow
)
240 SWELL_focused_oswindow
= hwnd
->m_oswindow
;
241 gdk_window_focus(hwnd
->m_oswindow
,GDK_CURRENT_TIME
);
246 void swell_recalcMinMaxInfo(HWND hwnd
)
248 if (!hwnd
|| !hwnd
->m_oswindow
|| !(hwnd
->m_style
& WS_CAPTION
)) return;
251 memset(&mmi
,0,sizeof(mmi
));
252 if (hwnd
->m_style
& WS_THICKFRAME
)
254 mmi
.ptMinTrackSize
.x
= 20;
255 mmi
.ptMaxSize
.x
= mmi
.ptMaxTrackSize
.x
= 16384;
256 mmi
.ptMinTrackSize
.y
= 20;
257 mmi
.ptMaxSize
.y
= mmi
.ptMaxTrackSize
.y
= 16384;
258 SendMessage(hwnd
,WM_GETMINMAXINFO
,0,(LPARAM
)&mmi
);
262 RECT r
=hwnd
->m_position
;
263 mmi
.ptMinTrackSize
.x
= mmi
.ptMaxSize
.x
= mmi
.ptMaxTrackSize
.x
= r
.right
-r
.left
;
264 mmi
.ptMinTrackSize
.y
= mmi
.ptMaxSize
.y
= mmi
.ptMaxTrackSize
.y
= r
.bottom
-r
.top
;
268 memset(&h
,0,sizeof(h
));
269 h
.max_width
= mmi
.ptMaxSize
.x
;
270 h
.max_height
= mmi
.ptMaxSize
.y
;
271 h
.min_width
= mmi
.ptMinTrackSize
.x
;
272 h
.min_height
= mmi
.ptMinTrackSize
.y
;
273 gdk_window_set_geometry_hints(hwnd
->m_oswindow
,&h
,(GdkWindowHints
) (GDK_HINT_POS
| GDK_HINT_MIN_SIZE
| GDK_HINT_MAX_SIZE
));
276 void SWELL_initargs(int *argc
, char ***argv
)
278 if (!SWELL_gdk_active
)
281 #if SWELL_TARGET_GDK == 3
282 void (*_gdk_set_allowed_backends
)(const char *);
284 *(void **)&_gdk_drag_drop_done
= dlsym(RTLD_DEFAULT
,"gdk_drag_drop_done");
285 *(void **)&_gdk_set_allowed_backends
= dlsym(RTLD_DEFAULT
,"gdk_set_allowed_backends");
287 if (_gdk_set_allowed_backends
)
288 _gdk_set_allowed_backends("x11");
291 #ifdef SWELL_SUPPORT_GTK
292 SWELL_gdk_active
= gtk_init_check(argc
,argv
) ? 1 : -1;
294 SWELL_gdk_active
= gdk_init_check(argc
,argv
) ? 1 : -1;
296 if (SWELL_gdk_active
> 0)
299 GetModuleFileName(NULL
,buf
,sizeof(buf
));
300 WDL_remove_filepart(buf
);
301 lstrcatn(buf
,"/Resources/main.png",sizeof(buf
));
302 GdkPixbuf
*pb
= gdk_pixbuf_new_from_file(buf
,NULL
);
305 strcpy(buf
+strlen(buf
)-3,"ico");
306 pb
= gdk_pixbuf_new_from_file(buf
,NULL
);
308 if (pb
) s_program_icon_list
= g_list_append(s_program_icon_list
,pb
);
310 gdk_event_handler_set(swell_gdkEventHandler
,NULL
,NULL
);
315 static bool swell_initwindowsys()
317 if (!SWELL_gdk_active
)
319 // maybe make the main app call this with real parms
327 SWELL_initargs(&argc
,&pargv
);
330 return SWELL_gdk_active
>0;
333 #ifdef SWELL_LICE_GDI
334 class LICE_CairoBitmap
: public LICE_IBitmap
340 m_allocsize
= m_width
= m_height
= m_span
= 0;
343 virtual ~LICE_CairoBitmap()
345 if (m_surf
) cairo_surface_destroy(m_surf
);
349 // LICE_IBitmap interface
350 virtual LICE_pixel
*getBits()
352 const UINT_PTR extra
=LICE_MEMBITMAP_ALIGNAMT
;
353 return (LICE_pixel
*) (((UINT_PTR
)m_fb
+ extra
)&~extra
);
356 virtual int getWidth() { return m_width
; }
357 virtual int getHeight() { return m_height
; }
358 virtual int getRowSpan() { return m_span
; }
359 virtual bool resize(int w
, int h
)
363 if (w
== m_width
&& h
== m_height
) return false;
365 if (m_surf
) cairo_surface_destroy(m_surf
);
368 m_span
= w
? cairo_format_stride_for_width(CAIRO_FORMAT_RGB24
,w
)/4 : 0;
369 const int sz
= h
* m_span
* 4 + LICE_MEMBITMAP_ALIGNAMT
;
370 if (!m_fb
|| m_allocsize
< sz
|| sz
< m_allocsize
/4)
372 const int newalloc
= m_allocsize
<sz
? (sz
*3)/2 : sz
;
373 void *p
= realloc(m_fb
,newalloc
);
374 if (!p
) return false;
376 m_fb
= (LICE_pixel
*)p
;
377 m_allocsize
= newalloc
;
380 m_width
=w
&& h
? w
:0;
381 m_height
=w
&& h
? h
: 0;
384 virtual INT_PTR
Extended(int id
, void* data
)
390 // in case we want to release surface
395 m_surf
= cairo_image_surface_create_for_data((guchar
*)getBits(), CAIRO_FORMAT_RGB24
,
396 getWidth(),getHeight(), getRowSpan()*4);
397 return (INT_PTR
)m_surf
;
404 int m_width
, m_height
, m_span
;
406 cairo_surface_t
*m_surf
;
410 static int swell_gdk_option(const char *name
, const char *defstr
, int defv
)
413 GetPrivateProfileString(".swell",name
,"",buf
,sizeof(buf
),"");
414 if (!buf
[0]) WritePrivateProfileString(".swell",name
,defstr
,"");
415 if (buf
[0] >= '0' && buf
[0] <= '9') return atoi(buf
);
419 static void init_options()
423 const char *wmname
= gdk_x11_screen_get_window_manager_name(gdk_screen_get_default ());
425 gdk_options
= 0x40000000;
427 if (swell_gdk_option("gdk_owned_windows_keep_above", "auto (default is 1)",1))
428 gdk_options
|=OPTION_KEEP_OWNED_ABOVE
;
430 if (swell_gdk_option("gdk_owned_windows_in_tasklist", "auto (default is 0)",0))
431 gdk_options
|=OPTION_OWNED_TASKLIST
;
433 if (swell_gdk_option("gdk_borderless_are_override_redirect", "auto (default is 0)", wmname
&& !stricmp(wmname
,"i3")))
434 gdk_options
|=OPTION_BORDERLESS_OVERRIDEREDIRECT
;
439 void swell_oswindow_manage(HWND hwnd
, bool wantfocus
)
443 bool isVis
= hwnd
->m_oswindow
!= NULL
;
444 bool wantVis
= !hwnd
->m_parent
&& hwnd
->m_visible
;
446 if (isVis
!= wantVis
)
451 GetWindowRect(hwnd
,&r
);
452 swell_oswindow_destroy(hwnd
);
453 hwnd
->m_position
= r
;
457 if (swell_initwindowsys())
460 SWELL_OSWINDOW transient_for
=NULL
;
461 if (hwnd
->m_owner
&& (gdk_options
&OPTION_KEEP_OWNED_ABOVE
))
463 HWND own
= hwnd
->m_owner
;
464 while (own
->m_parent
&& !own
->m_oswindow
) own
=own
->m_parent
;
465 transient_for
= own
->m_oswindow
;
467 if (!transient_for
) return; // defer
470 RECT r
= hwnd
->m_position
;
471 GdkWindowAttr attr
={0,};
472 attr
.title
= (char *)hwnd
->m_title
.Get();
473 attr
.event_mask
= GDK_ALL_EVENTS_MASK
|GDK_EXPOSURE_MASK
;
476 attr
.width
= r
.right
-r
.left
;
477 attr
.height
= r
.bottom
-r
.top
;
478 attr
.wclass
= GDK_INPUT_OUTPUT
;
479 const char *appname
= g_swell_appname
;
480 attr
.wmclass_name
= (gchar
*)appname
;
481 attr
.wmclass_class
= (gchar
*)appname
;
482 attr
.window_type
= GDK_WINDOW_TOPLEVEL
;
483 hwnd
->m_oswindow
= gdk_window_new(NULL
,&attr
,GDK_WA_X
|GDK_WA_Y
|(appname
?GDK_WA_WMCLASS
:0));
485 if (hwnd
->m_oswindow
)
487 bool override_redirect
=false;
488 const bool modal
= DialogBoxIsActive() == hwnd
;
490 if (!(hwnd
->m_style
& WS_CAPTION
))
492 if ((!hwnd
->m_classname
|| strcmp(hwnd
->m_classname
,"__SWELL_MENU")) && !(gdk_options
&OPTION_BORDERLESS_OVERRIDEREDIRECT
))
495 gdk_window_set_transient_for(hwnd
->m_oswindow
,transient_for
);
496 gdk_window_set_type_hint(hwnd
->m_oswindow
, GDK_WINDOW_TYPE_HINT_NORMAL
);
497 gdk_window_set_decorations(hwnd
->m_oswindow
,(GdkWMDecoration
) 0);
501 gdk_window_set_override_redirect(hwnd
->m_oswindow
,true);
502 override_redirect
=true;
504 if (!SWELL_topwindows
||
505 (SWELL_topwindows
==hwnd
&& !hwnd
->m_next
)) wantfocus
=true;
509 GdkWindowTypeHint type_hint
= GDK_WINDOW_TYPE_HINT_NORMAL
;
510 GdkWMDecoration decor
= (GdkWMDecoration
) (GDK_DECOR_ALL
| GDK_DECOR_MENU
);
512 if (!(hwnd
->m_style
&WS_THICKFRAME
))
513 decor
= (GdkWMDecoration
) (GDK_DECOR_BORDER
|GDK_DECOR_TITLE
|GDK_DECOR_MINIMIZE
);
517 gdk_window_set_transient_for(hwnd
->m_oswindow
,transient_for
);
519 gdk_window_set_modal_hint(hwnd
->m_oswindow
,true);
522 if (modal
) type_hint
= GDK_WINDOW_TYPE_HINT_DIALOG
;
524 gdk_window_set_type_hint(hwnd
->m_oswindow
,type_hint
);
525 gdk_window_set_decorations(hwnd
->m_oswindow
,decor
);
528 if (s_force_window_time
)
529 gdk_x11_window_set_user_time(hwnd
->m_oswindow
,s_force_window_time
);
531 if (!wantfocus
|| swell_app_is_inactive
)
532 gdk_window_set_focus_on_map(hwnd
->m_oswindow
,false);
534 #ifdef SWELL_LICE_GDI
535 if (!hwnd
->m_backingstore
) hwnd
->m_backingstore
= new LICE_CairoBitmap
;
537 if (!override_redirect
)
539 if (s_program_icon_list
)
540 gdk_window_set_icon_list(hwnd
->m_oswindow
,s_program_icon_list
);
542 if (hwnd
->m_owner
&& !(gdk_options
&OPTION_OWNED_TASKLIST
) && !override_redirect
)
544 gdk_window_set_skip_taskbar_hint(hwnd
->m_oswindow
,true);
546 else if (hwnd
->m_style
== WS_CHILD
)
548 // hack: parentless visible window with WS_CHILD set will
549 // not appear in taskbar
550 gdk_window_set_skip_taskbar_hint(hwnd
->m_oswindow
,true);
553 if (hwnd
->m_israised
&& !swell_app_is_inactive
)
554 gdk_window_set_keep_above(hwnd
->m_oswindow
,TRUE
);
556 gdk_window_register_dnd(hwnd
->m_oswindow
);
558 if (hwnd
->m_oswindow_fullscreen
)
559 gdk_window_fullscreen(hwnd
->m_oswindow
);
561 if (!swell_app_is_inactive
&& !s_force_window_time
)
562 gdk_window_show(hwnd
->m_oswindow
);
564 gdk_window_show_unraised(hwnd
->m_oswindow
);
566 if (s_last_desktop
>0)
567 _gdk_x11_window_move_to_desktop(hwnd
->m_oswindow
,s_last_desktop
-1);
569 if (!hwnd
->m_oswindow_fullscreen
)
571 if (hwnd
->m_has_had_position
)
572 gdk_window_move_resize(hwnd
->m_oswindow
,r
.left
,r
.top
,r
.right
-r
.left
,r
.bottom
-r
.top
);
574 gdk_window_resize(hwnd
->m_oswindow
,r
.right
-r
.left
,r
.bottom
-r
.top
);
577 if ((gdk_options
&OPTION_KEEP_OWNED_ABOVE
) && hwnd
->m_owned_list
)
579 HWND l
= SWELL_topwindows
;
582 if (!l
->m_oswindow
&& l
->m_owner
== hwnd
&& l
->m_visible
)
583 swell_oswindow_manage(l
,false);
591 if (wantVis
) swell_oswindow_update_text(hwnd
);
594 void swell_oswindow_updatetoscreen(HWND hwnd
, RECT
*rect
)
596 #ifdef SWELL_LICE_GDI
597 if (hwnd
&& hwnd
->m_backingstore
&& hwnd
->m_oswindow
)
599 LICE_IBitmap
*bm
= hwnd
->m_backingstore
;
600 LICE_SubBitmap
tmpbm(bm
,rect
->left
,rect
->top
,rect
->right
-rect
->left
,rect
->bottom
-rect
->top
);
602 GdkRectangle rrr
={rect
->left
,rect
->top
,rect
->right
-rect
->left
,rect
->bottom
-rect
->top
};
603 gdk_window_begin_paint_rect(hwnd
->m_oswindow
, &rrr
);
605 cairo_t
* crc
= gdk_cairo_create (hwnd
->m_oswindow
);
606 cairo_surface_t
*temp_surface
= (cairo_surface_t
*)bm
->Extended(0xca140,NULL
);
607 if (temp_surface
) cairo_set_source_surface(crc
, temp_surface
, 0,0);
611 gdk_window_end_paint(hwnd
->m_oswindow
);
613 if (temp_surface
) bm
->Extended(0xca140,temp_surface
); // release
619 #if SWELL_TARGET_GDK == 2
620 #define DEF_GKY(x) GDK_##x
622 #define DEF_GKY(x) GDK_KEY_##x
625 static guint
swell_gdkConvertKey(guint key
)
627 //gdk key to VK_ conversion
630 case DEF_GKY(KP_Home
):
631 case DEF_GKY(Home
): return VK_HOME
;
632 case DEF_GKY(KP_End
):
633 case DEF_GKY(End
): return VK_END
;
635 case DEF_GKY(Up
): return VK_UP
;
636 case DEF_GKY(KP_Down
):
637 case DEF_GKY(Down
): return VK_DOWN
;
638 case DEF_GKY(KP_Left
):
639 case DEF_GKY(Left
): return VK_LEFT
;
640 case DEF_GKY(KP_Right
):
641 case DEF_GKY(Right
): return VK_RIGHT
;
642 case DEF_GKY(KP_Page_Up
):
643 case DEF_GKY(Page_Up
): return VK_PRIOR
;
644 case DEF_GKY(KP_Page_Down
):
645 case DEF_GKY(Page_Down
): return VK_NEXT
;
646 case DEF_GKY(KP_Insert
):
647 case DEF_GKY(Insert
): return VK_INSERT
;
648 case DEF_GKY(KP_Delete
):
649 case DEF_GKY(Delete
): return VK_DELETE
;
650 case DEF_GKY(Escape
): return VK_ESCAPE
;
651 case DEF_GKY(BackSpace
): return VK_BACK
;
652 case DEF_GKY(KP_Enter
):
653 case DEF_GKY(Return
): return VK_RETURN
;
654 case DEF_GKY(ISO_Left_Tab
):
655 case DEF_GKY(Tab
): return VK_TAB
;
656 case DEF_GKY(F1
): return VK_F1
;
657 case DEF_GKY(F2
): return VK_F2
;
658 case DEF_GKY(F3
): return VK_F3
;
659 case DEF_GKY(F4
): return VK_F4
;
660 case DEF_GKY(F5
): return VK_F5
;
661 case DEF_GKY(F6
): return VK_F6
;
662 case DEF_GKY(F7
): return VK_F7
;
663 case DEF_GKY(F8
): return VK_F8
;
664 case DEF_GKY(F9
): return VK_F9
;
665 case DEF_GKY(F10
): return VK_F10
;
666 case DEF_GKY(F11
): return VK_F11
;
667 case DEF_GKY(F12
): return VK_F12
;
668 case DEF_GKY(KP_0
): return VK_NUMPAD0
;
669 case DEF_GKY(KP_1
): return VK_NUMPAD1
;
670 case DEF_GKY(KP_2
): return VK_NUMPAD2
;
671 case DEF_GKY(KP_3
): return VK_NUMPAD3
;
672 case DEF_GKY(KP_4
): return VK_NUMPAD4
;
673 case DEF_GKY(KP_5
): return VK_NUMPAD5
;
674 case DEF_GKY(KP_6
): return VK_NUMPAD6
;
675 case DEF_GKY(KP_7
): return VK_NUMPAD7
;
676 case DEF_GKY(KP_8
): return VK_NUMPAD8
;
677 case DEF_GKY(KP_9
): return VK_NUMPAD9
;
678 case DEF_GKY(KP_Multiply
): return VK_MULTIPLY
;
679 case DEF_GKY(KP_Add
): return VK_ADD
;
680 case DEF_GKY(KP_Separator
): return VK_SEPARATOR
;
681 case DEF_GKY(KP_Subtract
): return VK_SUBTRACT
;
682 case DEF_GKY(KP_Decimal
): return VK_DECIMAL
;
683 case DEF_GKY(KP_Divide
): return VK_DIVIDE
;
684 case DEF_GKY(Num_Lock
): return VK_NUMLOCK
;
689 static LRESULT
SendMouseMessage(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
691 if (!hwnd
|| !hwnd
->m_wndproc
) return -1;
692 if (!IsWindowEnabled(hwnd
))
694 if (msg
== WM_LBUTTONDOWN
|| msg
== WM_RBUTTONDOWN
|| msg
== WM_MBUTTONDOWN
||
695 msg
== WM_LBUTTONDBLCLK
|| msg
== WM_RBUTTONDBLCLK
|| msg
== WM_MBUTTONDBLCLK
)
697 HWND h
= DialogBoxIsActive();
698 if (h
) SetForegroundWindow(h
);
704 if (msg
!= WM_MOUSEWHEEL
&& !GetCapture())
706 DWORD p
=GetMessagePos();
708 htc
=hwnd
->m_wndproc(hwnd
,WM_NCHITTEST
,0,p
);
709 if (hwnd
->m_hashaddestroy
||!hwnd
->m_wndproc
)
711 return -1; // if somehow WM_NCHITTEST destroyed us, bail
714 if (htc
!=HTCLIENT
|| swell_window_wants_all_input() == hwnd
)
716 if (msg
==WM_MOUSEMOVE
) return hwnd
->m_wndproc(hwnd
,WM_NCMOUSEMOVE
,htc
,p
);
717 // if (msg==WM_MOUSEWHEEL) return hwnd->m_wndproc(hwnd,WM_NCMOUSEWHEEL,htc,p);
718 // if (msg==WM_MOUSEHWHEEL) return hwnd->m_wndproc(hwnd,WM_NCMOUSEHWHEEL,htc,p);
719 if (msg
==WM_LBUTTONUP
) return hwnd
->m_wndproc(hwnd
,WM_NCLBUTTONUP
,htc
,p
);
720 if (msg
==WM_LBUTTONDOWN
) return hwnd
->m_wndproc(hwnd
,WM_NCLBUTTONDOWN
,htc
,p
);
721 if (msg
==WM_LBUTTONDBLCLK
) return hwnd
->m_wndproc(hwnd
,WM_NCLBUTTONDBLCLK
,htc
,p
);
722 if (msg
==WM_RBUTTONUP
) return hwnd
->m_wndproc(hwnd
,WM_NCRBUTTONUP
,htc
,p
);
723 if (msg
==WM_RBUTTONDOWN
) return hwnd
->m_wndproc(hwnd
,WM_NCRBUTTONDOWN
,htc
,p
);
724 if (msg
==WM_RBUTTONDBLCLK
) return hwnd
->m_wndproc(hwnd
,WM_NCRBUTTONDBLCLK
,htc
,p
);
725 if (msg
==WM_MBUTTONUP
) return hwnd
->m_wndproc(hwnd
,WM_NCMBUTTONUP
,htc
,p
);
726 if (msg
==WM_MBUTTONDOWN
) return hwnd
->m_wndproc(hwnd
,WM_NCMBUTTONDOWN
,htc
,p
);
727 if (msg
==WM_MBUTTONDBLCLK
) return hwnd
->m_wndproc(hwnd
,WM_NCMBUTTONDBLCLK
,htc
,p
);
732 LRESULT ret
=hwnd
->m_wndproc(hwnd
,msg
,wParam
,lParam
);
734 if (msg
==WM_LBUTTONUP
|| msg
==WM_RBUTTONUP
|| msg
==WM_MOUSEMOVE
|| msg
==WM_MBUTTONUP
)
736 if (!GetCapture() && (hwnd
->m_hashaddestroy
|| !hwnd
->m_wndproc
|| !hwnd
->m_wndproc(hwnd
,WM_SETCURSOR
,(WPARAM
)hwnd
,htc
| (msg
<<16))))
738 SetCursor(SWELL_LoadCursor(IDC_ARROW
));
745 static int hex_parse(char c
)
747 if (c
>= '0' && c
<= '9') return c
-'0';
748 if (c
>= 'A' && c
<= 'F') return 10+c
-'A';
749 if (c
>= 'a' && c
<= 'f') return 10+c
-'a';
753 static GdkAtom
utf8atom()
756 if (!tmp
) tmp
= gdk_atom_intern_static_string("UTF8_STRING");
759 static GdkAtom
tgtatom()
762 if (!tmp
) tmp
= gdk_atom_intern_static_string("TARGETS");
765 static GdkAtom
urilistatom()
768 if (!tmp
) tmp
= gdk_atom_intern_static_string("text/uri-list");
773 static void OnSelectionRequestEvent(GdkEventSelection
*b
)
775 //printf("got sel req %s\n",gdk_atom_name(b->target));
776 GdkAtom prop
=GDK_NONE
;
778 if (swell_dragsrc_osw
&& b
->window
== swell_dragsrc_osw
)
780 if (swell_dragsrc_hwnd
)
782 if (b
->target
== tgtatom())
785 GdkAtom list
[] = { urilistatom() };
786 #if SWELL_TARGET_GDK == 2
787 GdkWindow
*pw
= gdk_window_lookup(b
->requestor
);
788 if (!pw
) pw
= gdk_window_foreign_new(b
->requestor
);
790 GdkWindow
*pw
= b
->requestor
;
793 gdk_property_change(pw
,prop
,GDK_SELECTION_TYPE_ATOM
,32, GDK_PROP_MODE_REPLACE
,(guchar
*)list
,(int) (sizeof(list
)/sizeof(list
[0])));
795 SendMessage(swell_dragsrc_hwnd
,WM_USER
+100,(WPARAM
)b
,(LPARAM
)&prop
);
798 else if (s_clipboard_setstate
)
800 if (b
->target
== tgtatom())
802 if (s_clipboard_setstate_fmt
)
805 GdkAtom list
[] = { s_clipboard_setstate_fmt
};
806 #if SWELL_TARGET_GDK == 2
807 GdkWindow
*pw
= gdk_window_lookup(b
->requestor
);
808 if (!pw
) pw
= gdk_window_foreign_new(b
->requestor
);
810 GdkWindow
*pw
= b
->requestor
;
813 gdk_property_change(pw
,prop
,GDK_SELECTION_TYPE_ATOM
,32, GDK_PROP_MODE_REPLACE
,(guchar
*)list
,(int) (sizeof(list
)/sizeof(list
[0])));
818 if (b
->target
== s_clipboard_setstate_fmt
||
819 (b
->target
== GDK_TARGET_STRING
&& s_clipboard_setstate_fmt
== utf8atom())
823 int len
= GlobalSize(s_clipboard_setstate
);
824 guchar
*ptr
= (guchar
*)s_clipboard_setstate
;
827 if (s_clipboard_setstate_fmt
== utf8atom())
829 const char *rd
= (const char *)s_clipboard_setstate
;
832 if (!strncmp(rd
,"\r\n",2))
840 ptr
= (guchar
*)str
.Get();
841 len
= str
.GetLength();
843 #if SWELL_TARGET_GDK == 2
844 GdkWindow
*pw
= gdk_window_lookup(b
->requestor
);
845 if (!pw
) pw
= gdk_window_foreign_new(b
->requestor
);
847 GdkWindow
*pw
= b
->requestor
;
850 gdk_property_change(pw
,prop
,b
->target
,8, GDK_PROP_MODE_REPLACE
,ptr
,len
);
854 gdk_selection_send_notify(b
->requestor
,b
->selection
,b
->target
,prop
,GDK_CURRENT_TIME
);
857 static void OnExposeEvent(GdkEventExpose
*exp
)
859 HWND hwnd
= swell_oswindow_to_hwnd(exp
->window
);
862 #ifdef SWELL_LICE_GDI
865 // don't use GetClientRect(),since we're getting it pre-NCCALCSIZE etc
868 cr
.right
= hwnd
->m_position
.right
- hwnd
->m_position
.left
;
869 cr
.bottom
= hwnd
->m_position
.bottom
- hwnd
->m_position
.top
;
871 r
.left
= exp
->area
.x
;
873 r
.bottom
=r
.top
+exp
->area
.height
;
874 r
.right
=r
.left
+exp
->area
.width
;
876 if (!hwnd
->m_backingstore
) hwnd
->m_backingstore
= new LICE_CairoBitmap
;
878 bool forceref
= hwnd
->m_backingstore
->resize(cr
.right
-cr
.left
,cr
.bottom
-cr
.top
);
879 if (forceref
) r
= cr
;
881 LICE_SubBitmap
tmpbm(hwnd
->m_backingstore
,r
.left
,r
.top
,r
.right
-r
.left
,r
.bottom
-r
.top
);
883 if (tmpbm
.getWidth()>0 && tmpbm
.getHeight()>0)
885 void SWELL_internalLICEpaint(HWND hwnd
, LICE_IBitmap
*bmout
, int bmout_xpos
, int bmout_ypos
, bool forceref
);
886 SWELL_internalLICEpaint(hwnd
, &tmpbm
, r
.left
, r
.top
, forceref
);
888 GdkRectangle rrr
={r
.left
,r
.top
,r
.right
-r
.left
,r
.bottom
-r
.top
};
889 gdk_window_begin_paint_rect(exp
->window
, &rrr
);
891 cairo_t
*crc
= gdk_cairo_create (exp
->window
);
892 LICE_IBitmap
*bm
= hwnd
->m_backingstore
;
893 cairo_surface_t
*temp_surface
= (cairo_surface_t
*)bm
->Extended(0xca140,NULL
);
894 if (temp_surface
) cairo_set_source_surface(crc
, temp_surface
, 0,0);
897 if (temp_surface
) bm
->Extended(0xca140,temp_surface
); // release
899 gdk_window_end_paint(exp
->window
);
904 static void OnConfigureEvent(GdkEventConfigure
*cfg
)
906 HWND hwnd
= swell_oswindow_to_hwnd(cfg
->window
);
909 if (cfg
->x
!= hwnd
->m_position
.left
||
910 cfg
->y
!= hwnd
->m_position
.top
||
911 !hwnd
->m_has_had_position
)
914 hwnd
->m_has_had_position
= true;
916 if (cfg
->width
!= hwnd
->m_position
.right
-hwnd
->m_position
.left
||
917 cfg
->height
!= hwnd
->m_position
.bottom
- hwnd
->m_position
.top
) flag
|=2;
918 hwnd
->m_position
.left
= cfg
->x
;
919 hwnd
->m_position
.top
= cfg
->y
;
920 hwnd
->m_position
.right
= cfg
->x
+ cfg
->width
;
921 hwnd
->m_position
.bottom
= cfg
->y
+ cfg
->height
;
922 if (flag
&1) SendMessage(hwnd
,WM_MOVE
,0,0);
923 if (flag
&2) SendMessage(hwnd
,WM_SIZE
,0,0);
924 if (!hwnd
->m_hashaddestroy
&& hwnd
->m_oswindow
) swell_recalcMinMaxInfo(hwnd
);
927 static void OnKeyEvent(GdkEventKey
*k
)
929 HWND hwnd
= swell_oswindow_to_hwnd(k
->window
);
933 if (k
->state
&GDK_CONTROL_MASK
) modifiers
|=FCONTROL
;
934 if (k
->state
&GDK_MOD1_MASK
) modifiers
|=FALT
;
935 if (k
->state
&SWELL_WINDOWSKEY_GDK_MASK
) modifiers
|=FLWIN
;
936 if (k
->state
&GDK_SHIFT_MASK
) modifiers
|=FSHIFT
;
938 UINT msgtype
= k
->type
== GDK_KEY_PRESS
? WM_KEYDOWN
: WM_KEYUP
;
940 guint kv
= swell_gdkConvertKey(k
->keyval
);
943 modifiers
|= FVIRTKEY
;
948 if (swell_is_virtkey_char(kv
))
950 if (kv
>= 'a' && kv
<= 'z')
953 swell_is_likely_capslock
= (modifiers
&FSHIFT
)!=0;
955 else if (kv
>= 'A' && kv
<= 'Z')
957 swell_is_likely_capslock
= (modifiers
&FSHIFT
)==0;
959 modifiers
|= FVIRTKEY
;
963 if (kv
>= DEF_GKY(Shift_L
) ||
964 (kv
>= DEF_GKY(ISO_Lock
) &&
965 kv
<= DEF_GKY(ISO_Last_Group_Lock
))
968 if (kv
== DEF_GKY(Shift_L
) || kv
== DEF_GKY(Shift_R
)) kv
= VK_SHIFT
;
969 else if (kv
== DEF_GKY(Control_L
) || kv
== DEF_GKY(Control_R
)) kv
= VK_CONTROL
;
970 else if (kv
== DEF_GKY(Alt_L
) || kv
== DEF_GKY(Alt_R
)) kv
= VK_MENU
;
971 else if (kv
== DEF_GKY(Super_L
) || kv
== DEF_GKY(Super_R
)) kv
= VK_LWIN
;
972 else return; // unknown modifie key
974 msgtype
= k
->type
== GDK_KEY_PRESS
? WM_SYSKEYDOWN
: WM_SYSKEYUP
;
979 guint v
= gdk_keyval_to_unicode(kv
);
984 // treat as ASCII, clear shift flag (?)
985 modifiers
&= ~FSHIFT
;
990 HWND foc
= GetFocusIncludeMenus();
991 if (foc
&& IsChild(hwnd
,foc
)) hwnd
=foc
;
992 else if (foc
&& foc
->m_oswindow
&& !(foc
->m_style
&WS_CAPTION
)) hwnd
=foc
; // for menus, event sent to other window due to gdk_window_set_override_redirect()
994 MSG msg
= { hwnd
, msgtype
, kv
, modifiers
, };
995 if (SWELLAppMain(SWELLAPP_PROCESSMESSAGE
,(INT_PTR
)&msg
,0)<=0)
996 SendMessage(hwnd
, msg
.message
, kv
, modifiers
);
999 static HWND
getMouseTarget(SWELL_OSWINDOW osw
, POINT p
, const HWND
*hwnd_has_osw
)
1001 HWND hwnd
= GetCapture();
1002 if (hwnd
) return hwnd
;
1003 hwnd
= hwnd_has_osw
? *hwnd_has_osw
: swell_oswindow_to_hwnd(osw
);
1004 if (!hwnd
|| swell_window_wants_all_input() == hwnd
) return hwnd
;
1005 return ChildWindowFromPoint(hwnd
,p
);
1008 static void OnMotionEvent(GdkEventMotion
*m
)
1010 swell_lastMessagePos
= MAKELONG(((int)m
->x_root
&0xffff),((int)m
->y_root
&0xffff));
1011 POINT p
={(int)m
->x
, (int)m
->y
};
1012 HWND hwnd
= getMouseTarget(m
->window
,p
,NULL
);
1016 POINT p2
={(int)m
->x_root
, (int)m
->y_root
};
1017 ScreenToClient(hwnd
, &p2
);
1018 if (hwnd
) hwnd
->Retain();
1019 SendMouseMessage(hwnd
, WM_MOUSEMOVE
, 0, MAKELPARAM(p2
.x
, p2
.y
));
1020 if (hwnd
) hwnd
->Release();
1024 static void OnScrollEvent(GdkEventScroll
*b
)
1026 swell_lastMessagePos
= MAKELONG(((int)b
->x_root
&0xffff),((int)b
->y_root
&0xffff));
1027 POINT p
={(int)b
->x
, (int)b
->y
};
1029 HWND hwnd
= getMouseTarget(b
->window
,p
,NULL
);
1032 POINT p2
={(int)b
->x_root
, (int)b
->y_root
};
1033 // p2 is screen coordinates for WM_MOUSEWHEEL
1035 int msg
=(b
->direction
== GDK_SCROLL_UP
|| b
->direction
== GDK_SCROLL_DOWN
) ? WM_MOUSEWHEEL
:
1036 (b
->direction
== GDK_SCROLL_LEFT
|| b
->direction
== GDK_SCROLL_RIGHT
) ? WM_MOUSEHWHEEL
: 0;
1040 int v
= (b
->direction
== GDK_SCROLL_UP
|| b
->direction
== GDK_SCROLL_LEFT
) ? 120 : -120;
1042 if (hwnd
) hwnd
->Retain();
1043 SendMouseMessage(hwnd
, msg
, (v
<<16), MAKELPARAM(p2
.x
, p2
.y
));
1044 if (hwnd
) hwnd
->Release();
1049 static void OnButtonEvent(GdkEventButton
*b
)
1051 HWND hwnd
= swell_oswindow_to_hwnd(b
->window
);
1053 swell_lastMessagePos
= MAKELONG(((int)b
->x_root
&0xffff),((int)b
->y_root
&0xffff));
1054 POINT p
={(int)b
->x
, (int)b
->y
};
1055 HWND hwnd2
= getMouseTarget(b
->window
,p
,&hwnd
);
1057 POINT p2
={(int)b
->x_root
, (int)b
->y_root
};
1058 ScreenToClient(hwnd2
, &p2
);
1060 int msg
=WM_LBUTTONDOWN
;
1061 if (b
->button
==2) msg
=WM_MBUTTONDOWN
;
1062 else if (b
->button
==3) msg
=WM_RBUTTONDOWN
;
1064 if (hwnd
&& hwnd
->m_oswindow
&& SWELL_focused_oswindow
!= hwnd
->m_oswindow
)
1066 SWELL_focused_oswindow
= hwnd
->m_oswindow
;
1069 if (hwnd2
) hwnd2
->Retain();
1071 // for doubleclicks, GDK actually seems to send:
1072 // GDK_BUTTON_PRESS, GDK_BUTTON_RELEASE,
1073 // GDK_BUTTON_PRESS, GDK_2BUTTON_PRESS, GDK_BUTTON_RELEASE
1075 // WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, WM_LBUTTONUP
1077 // WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDOWN, WM_LBUTTONUP,
1078 // WM_LBUTTONDBLCLK, WM_LBUTTONUP
1079 // there is an extra down/up pair, but it should behave fine with most code
1082 if(b
->type
== GDK_BUTTON_RELEASE
)
1084 msg
++; // convert WM_xBUTTONDOWN to WM_xBUTTONUP
1086 else if(b
->type
== GDK_2BUTTON_PRESS
)
1088 msg
++; // convert WM_xBUTTONDOWN to WM_xBUTTONUP
1089 SendMouseMessage(hwnd2
, msg
, 0, MAKELPARAM(p2
.x
, p2
.y
));
1090 msg
++; // convert WM_xBUTTONUP to WM_xBUTTONDBLCLK
1093 SendMouseMessage(hwnd2
, msg
, 0, MAKELPARAM(p2
.x
, p2
.y
));
1094 if (hwnd2
) hwnd2
->Release();
1098 static void OnSelectionNotifyEvent(GdkEventSelection
*b
)
1100 HWND hwnd
= swell_oswindow_to_hwnd(b
->window
);
1103 if (hwnd
== s_ddrop_hwnd
&& b
->target
== urilistatom())
1105 POINT p
= s_ddrop_pt
;
1108 GetWindowContentViewRect(hwnd
,&r
);
1113 cw
= ChildWindowFromPoint(hwnd
,p
);
1120 gint sz
=gdk_selection_property_get(b
->window
,&gptr
,&fmt
,&unitsz
);
1124 HANDLE gobj
=GlobalAlloc(0,sz
+sizeof(DROPFILES
));
1127 DROPFILES
*df
=(DROPFILES
*)gobj
;
1128 df
->pFiles
= sizeof(DROPFILES
);
1129 df
->pt
= s_ddrop_pt
;
1130 ScreenToClient(cw
,&df
->pt
);
1133 guchar
*pout
= (guchar
*)(df
+1);
1134 const guchar
*rd
= gptr
;
1135 const guchar
*rd_end
= rd
+ sz
;
1138 while (rd
< rd_end
&& *rd
&& isspace(*rd
)) rd
++;
1139 if (rd
>= rd_end
) break;
1141 if (rd
+7 < rd_end
&& !strnicmp((const char *)rd
,"file://",7))
1145 while (rd
< rd_end
&& *rd
&& !isspace(*rd
))
1148 if (*rd
== '%' && rd
+2 < rd_end
&& (v1
=hex_parse(rd
[1]))>=0 && (v2
=hex_parse(rd
[2]))>=0)
1150 *pout
++ = (v1
<<4) | v2
;
1163 while (rd
< rd_end
&& *rd
&& !isspace(*rd
)) rd
++;
1169 SendMessage(cw
,WM_DROPFILES
,(WPARAM
)gobj
,0);
1174 if (gptr
) g_free(gptr
);
1181 if (s_clipboard_getstate
) { GlobalFree(s_clipboard_getstate
); s_clipboard_getstate
=NULL
; }
1185 gint sz
=gdk_selection_property_get(b
->window
,&gptr
,&fmt
,&unitsz
);
1186 if (sz
>0 && gptr
&& (unitsz
== 8 || unitsz
== 16 || unitsz
== 32))
1190 if (fmt
== GDK_TARGET_STRING
|| fmt
== utf8atom())
1196 if (unitsz
==32) { c
= *(unsigned int *)ptr
; ptr
+=4; }
1197 else if (unitsz
==16) { c
= *(unsigned short *)ptr
; ptr
+=2; }
1202 if (c
== '\n' && lastc
!= '\r') str
.Append("\r",1);
1205 if (fmt
!= GDK_TARGET_STRING
)
1207 bv
[0] = (char) ((unsigned char)c
);
1212 WDL_MakeUTFChar(bv
,c
,sizeof(bv
));
1218 ptr
= (guchar
*)str
.Get();
1219 sz
=str
.GetLength()+1;
1221 else if (unitsz
>8) sz
*= (unitsz
/8);
1223 s_clipboard_getstate
= GlobalAlloc(0,sz
);
1224 if (s_clipboard_getstate
)
1226 memcpy(s_clipboard_getstate
,ptr
,sz
);
1227 s_clipboard_getstate_fmt
= fmt
;
1230 if (gptr
) g_free(gptr
);
1233 static void OnDropStartEvent(GdkEventDND
*e
)
1235 HWND hwnd
= swell_oswindow_to_hwnd(e
->window
);
1238 GdkDragContext
*ctx
= e
->context
;
1241 POINT p
= { (int)e
->x_root
, (int)e
->y_root
};
1242 s_ddrop_hwnd
= hwnd
;
1245 GdkAtom srca
= gdk_drag_get_selection(ctx
);
1246 gdk_selection_convert(e
->window
,srca
,urilistatom(),e
->time
);
1247 gdk_drop_finish(ctx
,TRUE
,e
->time
);
1251 static bool is_our_oswindow(GdkWindow
*w
)
1255 HWND hwnd
= swell_oswindow_to_hwnd(w
);
1256 if (hwnd
) return true;
1257 w
= gdk_window_get_effective_parent(w
);
1263 static void deactivateTimer(HWND hwnd
, UINT uMsg
, UINT_PTR tm
, DWORD dwt
)
1265 KillTimer(NULL
,s_deactivate_timer
);
1266 s_deactivate_timer
=0;
1267 if (swell_app_is_inactive
) return;
1268 GdkWindow
*window
= gdk_screen_get_active_window(gdk_screen_get_default());
1269 if (!is_our_oswindow(window
))
1274 static void swell_gdkEventHandler(GdkEvent
*evt
, gpointer data
)
1276 GdkEvent
*oldEvt
= s_cur_evt
;
1281 case GDK_FOCUS_CHANGE
:
1283 GdkEventFocus
*fc
= (GdkEventFocus
*)evt
;
1284 if (s_deactivate_timer
)
1286 KillTimer(NULL
,s_deactivate_timer
);
1287 s_deactivate_timer
=0;
1289 if (fc
->in
&& is_our_oswindow(fc
->window
))
1291 swell_on_toplevel_raise(fc
->window
);
1292 SWELL_focused_oswindow
= fc
->window
;
1293 if (swell_app_is_inactive
)
1298 else if (!swell_app_is_inactive
)
1300 GdkWindow
*window
= gdk_screen_get_active_window(gdk_screen_get_default());
1301 if (!is_our_oswindow(window
))
1307 s_deactivate_timer
= SetTimer(NULL
,0,200,deactivateTimer
);
1308 DestroyPopupMenus();
1313 case GDK_SELECTION_REQUEST
:
1314 OnSelectionRequestEvent((GdkEventSelection
*)evt
);
1319 HWND hwnd
= swell_oswindow_to_hwnd(((GdkEventAny
*)evt
)->window
);
1320 if (hwnd
&& IsWindowEnabled(hwnd
) && !SendMessage(hwnd
,WM_CLOSE
,0,0))
1321 SendMessage(hwnd
,WM_COMMAND
,IDCANCEL
,0);
1324 case GDK_EXPOSE
: // paint! GdkEventExpose...
1325 OnExposeEvent((GdkEventExpose
*)evt
);
1327 case GDK_CONFIGURE
: // size/move, GdkEventConfigure
1328 OnConfigureEvent((GdkEventConfigure
*)evt
);
1330 case GDK_WINDOW_STATE
: /// GdkEventWindowState for min/max
1331 //printf("minmax\n");
1333 case GDK_GRAB_BROKEN
:
1334 if (swell_oswindow_to_hwnd(((GdkEventAny
*)evt
)->window
))
1336 if (swell_captured_window
)
1338 SendMessage(swell_captured_window
,WM_CAPTURECHANGED
,0,0);
1339 swell_captured_window
=0;
1344 case GDK_KEY_RELEASE
:
1345 swell_dlg_destroyspare();
1346 OnKeyEvent((GdkEventKey
*)evt
);
1348 #ifdef GDK_AVAILABLE_IN_3_4
1349 case GDK_TOUCH_BEGIN
:
1350 case GDK_TOUCH_UPDATE
:
1352 case GDK_TOUCH_CANCEL
:
1354 GdkEventTouch
*e
= (GdkEventTouch
*)evt
;
1355 static guint32 touchptr_lasttime
;
1356 bool doubletap
= false;
1357 if (evt
->type
== GDK_TOUCH_BEGIN
&& !g_swell_touchptr
)
1359 DWORD now
= e
->time
;
1360 doubletap
= touchptr_lasttime
&&
1361 now
>= touchptr_lasttime
&&
1362 now
< touchptr_lasttime
+350;
1363 touchptr_lasttime
= now
;
1364 g_swell_touchptr
= e
->sequence
;
1365 g_swell_touchptr_wnd
= e
->window
;
1368 if (!e
->sequence
|| e
->sequence
!= g_swell_touchptr
)
1370 touchptr_lasttime
=0;
1374 if (e
->type
== GDK_TOUCH_UPDATE
)
1377 memset(&m
,0,sizeof(m
));
1378 m
.type
= GDK_MOTION_NOTIFY
;
1379 m
.window
= e
->window
;
1385 m
.device
= e
->device
;
1386 m
.x_root
= e
->x_root
;
1387 m
.y_root
= e
->y_root
;
1393 memset(&but
,0,sizeof(but
));
1394 if (e
->type
== GDK_TOUCH_BEGIN
)
1396 but
.type
= doubletap
? GDK_2BUTTON_PRESS
:GDK_BUTTON_PRESS
;
1400 but
.type
= GDK_BUTTON_RELEASE
;
1401 g_swell_touchptr
= NULL
;
1403 but
.window
= e
->window
;
1408 but
.state
= e
->state
;
1409 but
.device
= e
->device
;
1411 but
.x_root
= e
->x_root
;
1412 but
.y_root
= e
->y_root
;
1413 swell_dlg_destroyspare();
1414 OnButtonEvent(&but
);
1419 case GDK_MOTION_NOTIFY
:
1420 gdk_event_request_motions((GdkEventMotion
*)evt
);
1421 OnMotionEvent((GdkEventMotion
*)evt
);
1424 OnScrollEvent((GdkEventScroll
*)evt
);
1426 case GDK_BUTTON_PRESS
:
1427 case GDK_2BUTTON_PRESS
:
1428 case GDK_BUTTON_RELEASE
:
1429 swell_dlg_destroyspare();
1430 OnButtonEvent((GdkEventButton
*)evt
);
1432 case GDK_SELECTION_NOTIFY
:
1433 OnSelectionNotifyEvent((GdkEventSelection
*)evt
);
1435 case GDK_DRAG_ENTER
:
1436 case GDK_DRAG_MOTION
:
1437 if (swell_oswindow_to_hwnd(((GdkEventAny
*)evt
)->window
))
1439 GdkEventDND
*e
= (GdkEventDND
*)evt
;
1442 gdk_drag_status(e
->context
,GDK_ACTION_COPY
,e
->time
);
1443 //? gdk_drop_reply(e->context,TRUE,e->time);
1447 case GDK_DRAG_LEAVE
:
1448 case GDK_DRAG_STATUS
:
1449 case GDK_DROP_FINISHED
:
1451 case GDK_DROP_START
:
1452 OnDropStartEvent((GdkEventDND
*)evt
);
1456 //printf("msg: %d\n",evt->type);
1459 #ifdef SWELL_SUPPORT_GTK
1460 gtk_main_do_event(evt
);
1465 void SWELL_RunEvents()
1467 if (SWELL_gdk_active
>0)
1469 #if 0 && defined(SWELL_SUPPORT_GTK)
1470 // does not seem to be necessary
1471 while (gtk_events_pending())
1472 gtk_main_iteration();
1475 #if SWELL_TARGET_GDK == 2
1476 gdk_window_process_all_updates();
1479 GMainContext
*ctx
=g_main_context_default();
1480 while (g_main_context_iteration(ctx
,FALSE
))
1483 while (gdk_events_pending() && (evt
= gdk_event_get()))
1485 swell_gdkEventHandler(evt
,(gpointer
)1);
1486 gdk_event_free(evt
);
1493 void swell_oswindow_update_style(HWND hwnd
, LONG oldstyle
)
1495 const LONG val
= hwnd
->m_style
, ret
= oldstyle
;
1496 if (hwnd
->m_oswindow
&& ((ret
^val
)& WS_CAPTION
))
1498 gdk_window_hide(hwnd
->m_oswindow
);
1499 if (val
& WS_CAPTION
)
1501 if (val
& WS_THICKFRAME
)
1502 gdk_window_set_decorations(hwnd
->m_oswindow
,(GdkWMDecoration
) (GDK_DECOR_ALL
| GDK_DECOR_MENU
));
1504 gdk_window_set_decorations(hwnd
->m_oswindow
,(GdkWMDecoration
) (GDK_DECOR_BORDER
|GDK_DECOR_TITLE
|GDK_DECOR_MINIMIZE
));
1508 gdk_window_set_decorations(hwnd
->m_oswindow
,(GdkWMDecoration
) 0);
1510 hwnd
->m_oswindow_private
|= PRIVATE_NEEDSHOW
;
1514 void swell_oswindow_update_enable(HWND hwnd
)
1516 if (hwnd
->m_oswindow
&& !swell_app_is_inactive
)
1517 gdk_window_set_accept_focus(hwnd
->m_oswindow
,hwnd
->m_enabled
);
1520 int SWELL_SetWindowLevel(HWND hwnd
, int newlevel
)
1525 rv
= hwnd
->m_israised
? 1 : 0;
1526 hwnd
->m_israised
= newlevel
>0;
1527 if (hwnd
->m_oswindow
) gdk_window_set_keep_above(hwnd
->m_oswindow
,newlevel
>0 && !swell_app_is_inactive
);
1532 void SWELL_GetViewPort(RECT
*r
, const RECT
*sourcerect
, bool wantWork
)
1534 if (swell_initwindowsys())
1536 GdkScreen
*defscr
= gdk_screen_get_default();
1537 if (!defscr
) { r
->left
=r
->top
=0; r
->right
=r
->bottom
=1024; return; }
1538 gint idx
= sourcerect
? gdk_screen_get_monitor_at_point(defscr
,
1539 (sourcerect
->left
+sourcerect
->right
)/2,
1540 (sourcerect
->top
+sourcerect
->bottom
)/2) : 0;
1541 GdkRectangle rc
={0,0,1024,1024};
1542 gdk_screen_get_monitor_geometry(defscr
,idx
,&rc
);
1543 r
->left
=rc
.x
; r
->top
= rc
.y
;
1544 r
->right
=rc
.x
+rc
.width
;
1545 r
->bottom
=rc
.y
+rc
.height
;
1554 bool GetWindowRect(HWND hwnd
, RECT
*r
)
1556 if (!hwnd
) return false;
1557 if (hwnd
->m_oswindow
)
1559 gint x
=hwnd
->m_position
.left
,y
=hwnd
->m_position
.top
;
1561 // need to get the origin of the frame for consistency with SetWindowPos()
1562 gdk_window_get_root_origin(hwnd
->m_oswindow
,&x
,&y
);
1566 r
->right
=x
+ hwnd
->m_position
.right
- hwnd
->m_position
.left
;
1567 r
->bottom
= y
+ hwnd
->m_position
.bottom
- hwnd
->m_position
.top
;
1572 ClientToScreen(hwnd
,(LPPOINT
)r
);
1573 r
->right
= r
->left
+ hwnd
->m_position
.right
- hwnd
->m_position
.left
;
1574 r
->bottom
= r
->top
+ hwnd
->m_position
.bottom
- hwnd
->m_position
.top
;
1578 void swell_oswindow_begin_resize(SWELL_OSWINDOW wnd
)
1580 // make sure window is resizable (hints will be re-set on upcoming CONFIGURE event)
1581 gdk_window_set_geometry_hints(wnd
,NULL
,(GdkWindowHints
) 0);
1584 void swell_oswindow_resize(SWELL_OSWINDOW wnd
, int reposflag
, RECT f
)
1586 if ((reposflag
&3)==3) gdk_window_move_resize(wnd
,f
.left
,f
.top
,f
.right
-f
.left
,f
.bottom
-f
.top
);
1587 else if (reposflag
&2) gdk_window_resize(wnd
,f
.right
-f
.left
,f
.bottom
-f
.top
);
1588 else if (reposflag
&1) gdk_window_move(wnd
,f
.left
,f
.top
);
1591 void swell_oswindow_postresize(HWND hwnd
, RECT f
)
1593 if (hwnd
->m_oswindow
&& (hwnd
->m_oswindow_private
&PRIVATE_NEEDSHOW
) && !hwnd
->m_oswindow_fullscreen
)
1595 gdk_window_show(hwnd
->m_oswindow
);
1596 if (hwnd
->m_style
& WS_CAPTION
) gdk_window_unmaximize(hwnd
->m_oswindow
); // fixes Kwin
1597 gdk_window_move_resize(hwnd
->m_oswindow
,f
.left
,f
.top
,f
.right
-f
.left
,f
.bottom
-f
.top
); // fixes xfce
1598 hwnd
->m_oswindow_private
&= ~PRIVATE_NEEDSHOW
;
1602 void UpdateWindow(HWND hwnd
)
1604 #if SWELL_TARGET_GDK == 2
1607 while (hwnd
&& !hwnd
->m_oswindow
) hwnd
=hwnd
->m_parent
;
1608 if (hwnd
&& hwnd
->m_oswindow
) gdk_window_process_updates(hwnd
->m_oswindow
,true);
1613 void swell_oswindow_invalidate(HWND hwnd
, const RECT
*r
)
1620 gdkr
.width
= r
->right
-r
->left
;
1621 gdkr
.height
= r
->bottom
-r
->top
;
1624 gdk_window_invalidate_rect(hwnd
->m_oswindow
,r
? &gdkr
: NULL
,true);
1629 bool OpenClipboard(HWND hwndDlg
)
1631 s_clip_hwnd
=hwndDlg
? hwndDlg
: SWELL_topwindows
;
1632 if (s_clipboard_getstate
)
1634 GlobalFree(s_clipboard_getstate
);
1635 s_clipboard_getstate
= NULL
;
1637 s_clipboard_getstate_fmt
= NULL
;
1642 static HANDLE
req_clipboard(GdkAtom type
)
1644 if (s_clipboard_getstate_fmt
== type
) return s_clipboard_getstate
;
1646 HWND h
= s_clip_hwnd
;
1647 while (h
&& !h
->m_oswindow
) h
= h
->m_parent
;
1649 if (h
&& SWELL_gdk_active
> 0)
1651 if (s_clipboard_getstate
)
1653 GlobalFree(s_clipboard_getstate
);
1654 s_clipboard_getstate
=NULL
;
1656 gdk_selection_convert(h
->m_oswindow
,GDK_SELECTION_CLIPBOARD
,type
,GDK_CURRENT_TIME
);
1658 GMainContext
*ctx
=g_main_context_default();
1659 DWORD startt
= GetTickCount();
1662 while (!s_clipboard_getstate
&& g_main_context_iteration(ctx
,FALSE
))
1665 while (!s_clipboard_getstate
&& gdk_events_pending() && (evt
= gdk_event_get()))
1667 if (evt
->type
== GDK_SELECTION_NOTIFY
|| evt
->type
== GDK_SELECTION_REQUEST
)
1668 swell_gdkEventHandler(evt
,(gpointer
)1);
1669 gdk_event_free(evt
);
1673 if (s_clipboard_getstate
)
1675 if (s_clipboard_getstate_fmt
== type
) return s_clipboard_getstate
;
1679 DWORD now
= GetTickCount();
1680 if (now
< startt
-1000 || now
> startt
+500) break;
1687 void CloseClipboard()
1692 UINT
EnumClipboardFormats(UINT lastfmt
)
1696 // checking this causes issues (reentrancy, I suppose?)
1697 //if (req_clipboard(utf8atom()))
1700 if (lastfmt
== CF_TEXT
) lastfmt
= 0;
1706 if (!m_clip_recs
.Enumerate(x
++,&fmt
)) return 0;
1707 if (lastfmt
== 0) return fmt
;
1709 if ((UINT
)fmt
== lastfmt
) return m_clip_recs
.Enumerate(x
++,&fmt
) ? fmt
: 0;
1713 HANDLE
GetClipboardData(UINT type
)
1715 if (type
== CF_TEXT
)
1717 return req_clipboard(utf8atom());
1719 return m_clip_recs
.Get(type
);
1723 void EmptyClipboard()
1725 m_clip_recs
.DeleteAll();
1728 void SetClipboardData(UINT type
, HANDLE h
)
1730 if (type
== CF_TEXT
)
1732 if (s_clipboard_setstate
) { GlobalFree(s_clipboard_setstate
); s_clipboard_setstate
=NULL
; }
1733 s_clipboard_setstate_fmt
=NULL
;
1734 static GdkWindow
*w
;
1737 GdkWindowAttr attr
={0,};
1738 attr
.title
= (char *)"swell clipboard";
1739 attr
.event_mask
= GDK_ALL_EVENTS_MASK
;
1740 attr
.wclass
= GDK_INPUT_ONLY
;
1741 attr
.window_type
= GDK_WINDOW_TOPLEVEL
;
1742 w
= gdk_window_new(NULL
,&attr
,0);
1746 s_clipboard_setstate_fmt
= utf8atom();
1747 s_clipboard_setstate
= h
;
1748 gdk_selection_owner_set(w
,GDK_SELECTION_CLIPBOARD
,GDK_CURRENT_TIME
,TRUE
);
1752 if (h
) m_clip_recs
.Insert(type
,h
);
1753 else m_clip_recs
.Delete(type
);
1756 UINT
RegisterClipboardFormat(const char *desc
)
1758 if (!desc
|| !*desc
) return 0;
1760 const int n
= m_clip_curfmts
.GetSize();
1762 if (!strcmp(m_clip_curfmts
.Get(x
),desc
)) return x
+ 1;
1763 m_clip_curfmts
.Add(strdup(desc
));
1768 void GetCursorPos(POINT
*pt
)
1772 if (SWELL_gdk_active
>0)
1774 //#if SWELL_TARGET_GDK == 3
1775 // GdkDevice *dev=NULL;
1776 // if (s_cur_evt) dev = gdk_event_get_device(s_cur_evt);
1777 // if (!dev) dev = gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_display_get_default()));
1778 // if (dev) gdk_device_get_position(dev,NULL,&pt->x,&pt->y);
1780 gdk_display_get_pointer(gdk_display_get_default(),NULL
,&pt
->x
,&pt
->y
,NULL
);
1786 WORD
GetAsyncKeyState(int key
)
1788 if (SWELL_gdk_active
>0)
1790 GdkModifierType mod
=(GdkModifierType
)0;
1791 HWND h
= GetFocus();
1792 while (h
&& !h
->m_oswindow
) h
= h
->m_parent
;
1793 //#if SWELL_TARGET_GDK == 3
1794 // GdkDevice *dev=NULL;
1795 // if (s_cur_evt) dev = gdk_event_get_device(s_cur_evt);
1796 // if (!dev) dev = gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_display_get_default()));
1797 // if (dev) gdk_window_get_device_position(h? h->m_oswindow : gdk_get_default_root_window(),dev, NULL, NULL,&mod);
1799 gdk_window_get_pointer(h
? h
->m_oswindow
: gdk_get_default_root_window(),NULL
,NULL
,&mod
);
1802 if (key
== VK_LBUTTON
) return ((mod
&GDK_BUTTON1_MASK
)||g_swell_touchptr
)?0x8000:0;
1803 if (key
== VK_MBUTTON
) return (mod
&GDK_BUTTON2_MASK
)?0x8000:0;
1804 if (key
== VK_RBUTTON
) return (mod
&GDK_BUTTON3_MASK
)?0x8000:0;
1806 if (key
== VK_CONTROL
) return (mod
&GDK_CONTROL_MASK
)?0x8000:0;
1807 if (key
== VK_MENU
) return (mod
&GDK_MOD1_MASK
)?0x8000:0;
1808 if (key
== VK_SHIFT
) return (mod
&GDK_SHIFT_MASK
)?0x8000:0;
1809 if (key
== VK_LWIN
) return (mod
&SWELL_WINDOWSKEY_GDK_MASK
)?0x8000:0;
1814 DWORD
GetMessagePos()
1816 return swell_lastMessagePos
;
1819 struct bridgeState
{
1820 bridgeState(bool needrep
, GdkWindow
*_w
, Window _nw
, Display
*_disp
);
1826 Display
*native_disp
;
1833 static WDL_PtrList
<bridgeState
> filter_windows
;
1834 bridgeState::~bridgeState()
1836 filter_windows
.DeletePtr(this);
1837 if (w
) gdk_window_destroy(w
);
1839 bridgeState::bridgeState(bool needrep
, GdkWindow
*_w
, Window _nw
, Display
*_disp
)
1845 need_reparent
=needrep
;
1846 memset(&lastrect
,0,sizeof(lastrect
));
1847 filter_windows
.Add(this);
1850 static LRESULT
xbridgeProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1855 if (hwnd
&& hwnd
->m_private_data
)
1857 bridgeState
*bs
= (bridgeState
*)hwnd
->m_private_data
;
1858 hwnd
->m_private_data
= 0;
1863 if (wParam
!= 1) break;
1866 if (hwnd
&& hwnd
->m_private_data
)
1868 bridgeState
*bs
= (bridgeState
*)hwnd
->m_private_data
;
1871 HWND h
= hwnd
->m_parent
;
1872 RECT tr
= hwnd
->m_position
;
1875 RECT cr
= h
->m_position
;
1878 cr
.right
-= cr
.left
;
1879 cr
.bottom
-= cr
.top
;
1885 NCCALCSIZE_PARAMS p
= {{ cr
}};
1886 h
->m_wndproc(h
,WM_NCCALCSIZE
,0,(LPARAM
)&p
);
1891 tr
.right
+= cr
.left
;
1892 tr
.bottom
+= cr
.top
;
1894 if (tr
.left
< cr
.left
) tr
.left
=cr
.left
;
1895 if (tr
.top
< cr
.top
) tr
.top
= cr
.top
;
1896 if (tr
.right
> cr
.right
) tr
.right
= cr
.right
;
1897 if (tr
.bottom
> cr
.bottom
) tr
.bottom
= cr
.bottom
;
1899 if (h
->m_oswindow
) break;
1903 // todo: need to periodically check to see if the plug-in has resized its window
1904 bool vis
= IsWindowVisible(hwnd
);
1907 #if SWELL_TARGET_GDK == 2
1909 gdk_window_get_geometry(bs
->w
,NULL
,NULL
,&w
,&hh
,&d
);
1912 gdk_window_get_geometry(bs
->w
,NULL
,NULL
,&w
,&hh
);
1914 if (w
> bs
->lastrect
.right
-bs
->lastrect
.left
)
1916 bs
->lastrect
.right
= bs
->lastrect
.left
+ w
;
1917 tr
.right
++; // workaround "bug" in GDK -- if bs->w was resized via Xlib, GDK won't resize it unless it thinks the size changed
1919 if (hh
> bs
->lastrect
.bottom
-bs
->lastrect
.top
)
1921 bs
->lastrect
.bottom
= bs
->lastrect
.top
+ hh
;
1922 tr
.bottom
++; // workaround "bug" in GDK -- if bs->w was resized via Xlib, GDK won't resize it unless it thinks the size changed
1926 if (h
&& (bs
->need_reparent
|| (vis
!= bs
->lastvis
) || (vis
&&memcmp(&tr
,&bs
->lastrect
,sizeof(RECT
)))))
1928 if (bs
->lastvis
&& !vis
)
1930 gdk_window_hide(bs
->w
);
1931 bs
->lastvis
= false;
1934 if (bs
->need_reparent
)
1936 gdk_window_reparent(bs
->w
,h
->m_oswindow
,tr
.left
,tr
.top
);
1937 gdk_window_resize(bs
->w
, tr
.right
-tr
.left
,tr
.bottom
-tr
.top
);
1940 bs
->need_reparent
=false;
1942 else if (memcmp(&tr
,&bs
->lastrect
,sizeof(RECT
)))
1945 gdk_window_move_resize(bs
->w
,tr
.left
,tr
.top
, tr
.right
-tr
.left
, tr
.bottom
-tr
.top
);
1947 if (vis
&& !bs
->lastvis
)
1949 gdk_window_show(bs
->w
);
1950 gdk_window_raise(bs
->w
);
1958 return DefWindowProc(hwnd
,uMsg
,wParam
,lParam
);
1961 static GdkFilterReturn
filterCreateShowProc(GdkXEvent
*xev
, GdkEvent
*event
, gpointer data
)
1963 const XEvent
*xevent
= (XEvent
*)xev
;
1964 if (xevent
&& xevent
->type
== CreateNotify
)
1966 for (int x
=0;x
<filter_windows
.GetSize(); x
++)
1968 bridgeState
*bs
= filter_windows
.Get(x
);
1969 if (bs
&& bs
->native_w
== xevent
->xany
.window
&& bs
->native_disp
== xevent
->xany
.display
)
1972 //gdk_window_get_geometry(bs->w,NULL,NULL,&w,&hh);
1973 XMapWindow(bs
->native_disp
, xevent
->xcreatewindow
.window
);
1974 //XResizeWindow(bs->native_disp, xevent->xcreatewindow.window,w,hh);
1975 return GDK_FILTER_REMOVE
;
1979 return GDK_FILTER_CONTINUE
;
1982 HWND
SWELL_CreateXBridgeWindow(HWND viewpar
, void **wref
, RECT
*r
)
1987 GdkWindow
*ospar
= NULL
;
1988 HWND hpar
= viewpar
;
1991 ospar
= hpar
->m_oswindow
;
1993 hpar
= hpar
->m_parent
;
1996 bool need_reparent
=false;
2000 need_reparent
= true;
2001 ospar
= gdk_screen_get_root_window(gdk_screen_get_default());
2004 Display
*disp
= gdk_x11_display_get_xdisplay(gdk_window_get_display(ospar
));
2005 Window w
= XCreateWindow(disp
,GDK_WINDOW_XID(ospar
),0,0,r
->right
-r
->left
,r
->bottom
-r
->top
,0,CopyFromParent
, InputOutput
, CopyFromParent
, 0, NULL
);
2006 GdkWindow
*gdkw
= w
? gdk_x11_window_foreign_new_for_display(gdk_display_get_default(),w
) : NULL
;
2008 hwnd
= new HWND__(viewpar
,0,r
,NULL
, true, xbridgeProc
);
2009 bridgeState
*bs
= gdkw
? new bridgeState(need_reparent
,gdkw
,w
,disp
) : NULL
;
2010 hwnd
->m_private_data
= (INT_PTR
) bs
;
2015 XSelectInput(disp
, w
, StructureNotifyMask
| SubstructureNotifyMask
);
2017 static bool filt_add
;
2021 gdk_window_add_filter(NULL
, filterCreateShowProc
, NULL
);
2023 SetTimer(hwnd
,1,100,NULL
);
2024 if (!need_reparent
) SendMessage(hwnd
,WM_SIZE
,0,0);
2029 struct dropSourceInfo
{
2032 srclist
=NULL
; srccount
=0; srcfn
=NULL
; callback
=NULL
;
2041 if (_gdk_drag_drop_done
) _gdk_drag_drop_done(dragctx
,state
!=0);
2042 g_object_unref(dragctx
);
2046 const char **srclist
;
2049 void (*callback
)(const char *);
2054 GdkDragContext
*dragctx
;
2057 static void encode_uri(WDL_FastString
*s
, const char *rd
)
2061 // unsure if UTF-8 chars should be urlencoded or allowed?
2062 if (*rd
< 0 || (!isalnum(*rd
) && *rd
!= '-' && *rd
!= '_' && *rd
!= '.' && *rd
!= '/'))
2065 snprintf(buf
,sizeof(buf
),"%%%02x",(int)(unsigned char)*rd
);
2068 else s
->Append(rd
,1);
2075 static LRESULT WINAPI
dropSourceWndProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2077 dropSourceInfo
*inf
= (dropSourceInfo
*)hwnd
->m_private_data
;
2081 if (!swell_dragsrc_osw
)
2083 GdkWindowAttr attr
={0,};
2084 attr
.title
= (char *)"swell drag source";
2085 attr
.event_mask
= GDK_ALL_EVENTS_MASK
;
2086 attr
.wclass
= GDK_INPUT_ONLY
;
2087 attr
.window_type
= GDK_WINDOW_TOPLEVEL
;
2088 swell_dragsrc_osw
= gdk_window_new(NULL
,&attr
,0);
2090 if (swell_dragsrc_osw
)
2092 inf
->dragctx
= gdk_drag_begin(swell_dragsrc_osw
, g_list_append(NULL
,urilistatom()));
2101 GdkWindow
*w
= NULL
;
2102 GdkDragProtocol proto
;
2103 gdk_drag_find_window_for_screen(inf
->dragctx
,NULL
,gdk_screen_get_default(),p
.x
,p
.y
,&w
,&proto
);
2104 // todo: need to update gdk_drag_context_get_drag_window()
2105 // (or just SetCursor() a drag and drop cursor)
2108 gdk_drag_motion(inf
->dragctx
,w
,proto
,p
.x
,p
.y
,GDK_ACTION_COPY
,GDK_ACTION_COPY
,GDK_CURRENT_TIME
);
2113 if (inf
->dragctx
&& !inf
->state
)
2116 GdkAtom sel
= gdk_drag_get_selection(inf
->dragctx
);
2117 if (sel
) gdk_selection_owner_set(swell_dragsrc_osw
,sel
,GDK_CURRENT_TIME
,TRUE
);
2118 gdk_drag_drop(inf
->dragctx
,GDK_CURRENT_TIME
);
2121 sel
= gdk_drag_get_selection(inf
->dragctx
);
2122 if (sel
) gdk_selection_owner_set(swell_dragsrc_osw
,sel
,GDK_CURRENT_TIME
,TRUE
);
2124 swell_dragsrc_timeout
= GetTickCount() + 500;
2130 if (wParam
&& lParam
)
2132 GdkAtom
*aOut
= (GdkAtom
*)lParam
;
2133 GdkEventSelection
*evt
= (GdkEventSelection
*)wParam
;
2135 if (evt
->target
== urilistatom())
2138 if (inf
->srclist
&& inf
->srccount
)
2140 for (int x
=0;x
<inf
->srccount
;x
++)
2142 if (x
) s
.Append("\n");
2143 s
.Append("file://");
2144 encode_uri(&s
,inf
->srclist
[x
]);
2147 else if (inf
->callback
&& inf
->srcfn
&& inf
->state
)
2149 inf
->callback(inf
->srcfn
);
2150 s
.Append("file://");
2151 encode_uri(&s
,inf
->srcfn
);
2156 *aOut
= evt
->property
;
2157 #if SWELL_TARGET_GDK == 2
2158 GdkWindow
*pw
= gdk_window_lookup(evt
->requestor
);
2159 if (!pw
) pw
= gdk_window_foreign_new(evt
->requestor
);
2161 GdkWindow
*pw
= evt
->requestor
;
2164 gdk_property_change(pw
,*aOut
,evt
->target
,8, GDK_PROP_MODE_REPLACE
,(guchar
*)s
.Get(),s
.GetLength());
2168 if (inf
->state
) ReleaseCapture();
2173 return DefWindowProc(hwnd
,msg
,wParam
,lParam
);
2177 void SWELL_InitiateDragDrop(HWND hwnd
, RECT
* srcrect
, const char* srcfn
, void (*callback
)(const char* dropfn
))
2179 dropSourceInfo info
;
2180 info
.srcfn
= strdup(srcfn
);
2181 info
.callback
= callback
;
2183 HWND__
*h
= new HWND__(NULL
,0,&r
,NULL
,false,NULL
,dropSourceWndProc
, NULL
);
2184 swell_dragsrc_timeout
= 0;
2185 swell_dragsrc_hwnd
=h
;
2186 h
->m_private_data
= (INT_PTR
) &info
;
2187 dropSourceWndProc(h
,WM_CREATE
,0,0);
2188 while (GetCapture()==h
)
2192 if (swell_dragsrc_timeout
&& GetTickCount()>swell_dragsrc_timeout
) ReleaseCapture();
2195 swell_dragsrc_hwnd
=NULL
;
2199 // owner owns srclist, make copies here etc
2200 void SWELL_InitiateDragDropOfFileList(HWND hwnd
, RECT
*srcrect
, const char **srclist
, int srccount
, HICON icon
)
2202 dropSourceInfo info
;
2203 info
.srclist
= srclist
;
2204 info
.srccount
= srccount
;
2206 HWND__
*h
= new HWND__(NULL
,0,&r
,NULL
,false,NULL
,dropSourceWndProc
, NULL
);
2207 swell_dragsrc_timeout
= 0;
2208 swell_dragsrc_hwnd
=h
;
2209 h
->m_private_data
= (INT_PTR
) &info
;
2210 dropSourceWndProc(h
,WM_CREATE
,0,0);
2211 while (GetCapture()==h
)
2215 if (swell_dragsrc_timeout
&& GetTickCount()>swell_dragsrc_timeout
) ReleaseCapture();
2218 swell_dragsrc_hwnd
=NULL
;
2222 void SWELL_FinishDragDrop() { }
2225 bool SWELL_IsCursorVisible()
2227 return s_cursor_vis_cnt
>=0;
2231 void SWELL_SetCursor(HCURSOR curs
)
2233 if (s_last_setcursor
== curs
&& SWELL_focused_oswindow
== s_last_setcursor_oswnd
) return;
2235 s_last_setcursor
=curs
;
2236 s_last_setcursor_oswnd
= SWELL_focused_oswindow
;
2237 if (SWELL_focused_oswindow
)
2239 gdk_window_set_cursor(SWELL_focused_oswindow
,(GdkCursor
*)curs
);
2240 #ifdef SWELL_TARGET_GDK_CURSORHACK
2243 // workaround for a GDK behavior:
2244 // gdkwindow.c, gdk_window_set_cursor_internal() has a line:
2245 // >>> if (_gdk_window_event_parent_of (window, pointer_info->window_under_pointer))
2246 // this should also allow setting the cursor if window is in a "grabbing" state
2247 GdkDisplay
*gdkdisp
= gdk_display_get_default();
2248 #if SWELL_TARGET_GDK == 2
2249 if (gdkdisp
&& gdk_display_get_window_at_pointer(gdkdisp
,NULL
,NULL
) != SWELL_focused_oswindow
)
2251 GdkDevice
*dev
= gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdkdisp
));
2252 if (dev
&& gdk_device_get_window_at_position(dev
,NULL
,NULL
) != SWELL_focused_oswindow
)
2255 Display
*disp
= gdk_x11_display_get_xdisplay(gdkdisp
);
2256 Window wn
= GDK_WINDOW_XID(SWELL_focused_oswindow
);
2257 #if SWELL_TARGET_GDK == 2
2258 gint devid
=2; // hardcoded default pointing device
2260 gint devid
= gdk_x11_device_get_id(dev
);
2265 XIDefineCursor(disp
,devid
,wn
, gdk_x11_cursor_get_xcursor((GdkCursor
*)curs
));
2267 XIUndefineCursor(disp
,devid
,wn
);
2271 #endif // SWELL_TARGET_GDK_CURSORHACK
2275 HCURSOR
SWELL_GetCursor()
2277 return s_last_setcursor
;
2279 HCURSOR
SWELL_GetLastSetCursor()
2281 return s_last_setcursor
;
2284 int SWELL_ShowCursor(BOOL bShow
)
2286 s_cursor_vis_cnt
+= (bShow
?1:-1);
2287 if (s_cursor_vis_cnt
==-1 && !bShow
)
2290 #if SWELL_TARGET_GDK == 3
2291 GdkDevice
*dev
= gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (gdk_display_get_default ()));
2292 gdk_device_get_position (dev
, NULL
, &x1
, &y1
);
2294 gdk_display_get_pointer(gdk_display_get_default(), NULL
, &x1
, &y1
, NULL
);
2296 g_swell_mouse_relmode_curpos_x
= x1
;
2297 g_swell_mouse_relmode_curpos_y
= y1
;
2298 s_last_cursor
= GetCursor();
2299 SetCursor((HCURSOR
)gdk_cursor_new_for_display(gdk_display_get_default(),GDK_BLANK_CURSOR
));
2300 g_swell_mouse_relmode
=true;
2302 if (s_cursor_vis_cnt
==0 && bShow
)
2304 SetCursor(s_last_cursor
);
2305 g_swell_mouse_relmode
=false;
2306 if (!g_swell_touchptr
)
2308 #if SWELL_TARGET_GDK == 3
2309 gdk_device_warp(gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_display_get_default())),
2310 gdk_screen_get_default(),
2311 g_swell_mouse_relmode_curpos_x
, g_swell_mouse_relmode_curpos_y
);
2313 gdk_display_warp_pointer(gdk_display_get_default(),gdk_screen_get_default(), g_swell_mouse_relmode_curpos_x
, g_swell_mouse_relmode_curpos_y
);
2317 return s_cursor_vis_cnt
;
2320 BOOL
SWELL_SetCursorPos(int X
, int Y
)
2322 if (g_swell_mouse_relmode
|| g_swell_touchptr
) return false;
2324 #if SWELL_TARGET_GDK == 3
2325 gdk_device_warp(gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_display_get_default())),
2326 gdk_screen_get_default(),
2329 gdk_display_warp_pointer(gdk_display_get_default(),gdk_screen_get_default(), X
, Y
);
2334 static void getHotSpotForFile(const char *fn
, POINT
*pt
)
2336 FILE *fp
= fopen(fn
,"rb");
2338 unsigned char buf
[32];
2339 if (fread(buf
,1,6,fp
)==6 && !buf
[0] && !buf
[1] && buf
[2] == 2 && buf
[3] == 0 && buf
[4] == 1 && buf
[5] == 0)
2342 pt
->x
= buf
[4]|(buf
[5]<<8);
2343 pt
->y
= buf
[6]|(buf
[7]<<8);
2348 HCURSOR
SWELL_LoadCursorFromFile(const char *fn
)
2350 GdkPixbuf
*pb
= gdk_pixbuf_new_from_file(fn
,NULL
);
2354 getHotSpotForFile(fn
,&hs
);
2355 GdkCursor
*curs
= gdk_cursor_new_from_pixbuf(gdk_display_get_default(),pb
,hs
.x
,hs
.y
);
2357 return (HCURSOR
) curs
;
2362 HCURSOR
SWELL_LoadCursor(const char *_idx
)
2364 GdkCursorType def
= GDK_LEFT_PTR
;
2365 if (_idx
== IDC_NO
) def
= GDK_PIRATE
;
2366 else if (_idx
== IDC_SIZENWSE
) def
= GDK_BOTTOM_LEFT_CORNER
;
2367 else if (_idx
== IDC_SIZENESW
) def
= GDK_BOTTOM_RIGHT_CORNER
;
2368 else if (_idx
== IDC_SIZEALL
) def
= GDK_FLEUR
;
2369 else if (_idx
== IDC_SIZEWE
) def
= GDK_RIGHT_SIDE
;
2370 else if (_idx
== IDC_SIZENS
) def
= GDK_TOP_SIDE
;
2371 else if (_idx
== IDC_ARROW
) def
= GDK_LEFT_PTR
;
2372 else if (_idx
== IDC_HAND
) def
= GDK_HAND1
;
2373 else if (_idx
== IDC_UPARROW
) def
= GDK_CENTER_PTR
;
2374 else if (_idx
== IDC_IBEAM
) def
= GDK_XTERM
;
2377 SWELL_CursorResourceIndex
*p
= SWELL_curmodule_cursorresource_head
;
2380 if (p
->resid
== _idx
)
2382 if (p
->cachedCursor
) return p
->cachedCursor
;
2383 // todo: load from p->resname, into p->cachedCursor, p->hotspot
2385 GetModuleFileName(NULL
,buf
,sizeof(buf
));
2386 WDL_remove_filepart(buf
);
2387 snprintf_append(buf
,sizeof(buf
),"/Resources/%s.cur",p
->resname
);
2388 GdkPixbuf
*pb
= gdk_pixbuf_new_from_file(buf
,NULL
);
2391 getHotSpotForFile(buf
,&p
->hotspot
);
2392 GdkCursor
*curs
= gdk_cursor_new_from_pixbuf(gdk_display_get_default(),pb
,p
->hotspot
.x
,p
->hotspot
.y
);
2393 return (p
->cachedCursor
= (HCURSOR
) curs
);
2400 HCURSOR hc
= (HCURSOR
)gdk_cursor_new_for_display(gdk_display_get_default(),def
);
2405 void SWELL_Register_Cursor_Resource(const char *idx
, const char *name
, int hotspot_x
, int hotspot_y
)
2407 SWELL_CursorResourceIndex
*ri
= (SWELL_CursorResourceIndex
*)malloc(sizeof(SWELL_CursorResourceIndex
));
2408 ri
->hotspot
.x
= hotspot_x
;
2409 ri
->hotspot
.y
= hotspot_y
;
2413 ri
->_next
= SWELL_curmodule_cursorresource_head
;
2414 SWELL_curmodule_cursorresource_head
= ri
;
2417 int SWELL_KeyToASCII(int wParam
, int lParam
, int *newflags
)