Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / swell / swell-generic-gdk.cpp
bloba87eadd4edc9b2e1f5c850018ae3d981b776e53f
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
26 #include "swell.h"
28 #ifdef SWELL_PRELOAD
29 #define STR(x) #x
30 #define STR2(x) STR(x)
31 extern "C" {
32 char __attribute__ ((visibility ("default"))) SWELL_WANT_LOAD_LIBRARY[] = STR2(SWELL_PRELOAD);
34 #undef STR
35 #undef STR2
36 #endif
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>
49 #endif
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)
57 Atom type;
58 gint format;
59 gulong nitems=0, bytes_after;
60 guchar *data;
62 if (!window || !gdk_x11_screen_supports_net_wm_hint(gdk_window_get_screen(window),
63 gdk_atom_intern_static_string("_NET_WM_DESKTOP")))
64 return 0;
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;
71 XFree(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")))
81 return;
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");
88 xclient.format = 32;
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
101 #endif
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;
152 while (h)
154 if (h->m_oswindow)
156 if (h->m_israised)
157 gdk_window_set_keep_above(h->m_oswindow,TRUE);
159 if (!h->m_enabled)
160 gdk_window_set_accept_focus(h->m_oswindow,FALSE);
163 PostMessage(h,WM_ACTIVATEAPP,1,0);
164 h=h->m_next;
166 s_last_desktop=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;
177 while (h)
179 if (h->m_oswindow)
181 if (h->m_israised)
182 gdk_window_set_keep_above(h->m_oswindow,FALSE);
183 if (!h->m_enabled)
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);
187 h=h->m_next;
189 DestroyPopupMenus();
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;
204 #endif
206 if (swell_app_is_inactive)
208 HWND h = SWELL_topwindows;
209 while (h)
211 if (h->m_oswindow) break;
212 h = h->m_next;
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)
228 if (!hwnd)
230 SWELL_focused_oswindow = NULL;
231 return;
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;
250 MINMAXINFO mmi;
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);
260 else
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;
267 GdkGeometry h;
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)
280 XInitThreads();
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");
289 #endif
291 #ifdef SWELL_SUPPORT_GTK
292 SWELL_gdk_active = gtk_init_check(argc,argv) ? 1 : -1;
293 #else
294 SWELL_gdk_active = gdk_init_check(argc,argv) ? 1 : -1;
295 #endif
296 if (SWELL_gdk_active > 0)
298 char buf[1024];
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);
303 if (!pb)
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
320 int argc=1;
321 char buf[32];
322 strcpy(buf,"blah");
323 char *argv[2];
324 argv[0] = buf;
325 argv[1] = buf;
326 char **pargv = argv;
327 SWELL_initargs(&argc,&pargv);
330 return SWELL_gdk_active>0;
333 #ifdef SWELL_LICE_GDI
334 class LICE_CairoBitmap : public LICE_IBitmap
336 public:
337 LICE_CairoBitmap()
339 m_fb = NULL;
340 m_allocsize = m_width = m_height = m_span = 0;
341 m_surf = NULL;
343 virtual ~LICE_CairoBitmap()
345 if (m_surf) cairo_surface_destroy(m_surf);
346 free(m_fb);
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)
361 if (w<0) w=0;
362 if (h<0) h=0;
363 if (w == m_width && h == m_height) return false;
365 if (m_surf) cairo_surface_destroy(m_surf);
366 m_surf = NULL;
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;
382 return true;
384 virtual INT_PTR Extended(int id, void* data)
386 if (id == 0xca140)
388 if (data)
390 // in case we want to release surface
391 return 0;
394 if (!m_surf)
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;
399 return 0;
402 private:
403 LICE_pixel *m_fb;
404 int m_width, m_height, m_span;
405 int m_allocsize;
406 cairo_surface_t *m_surf;
408 #endif
410 static int swell_gdk_option(const char *name, const char *defstr, int defv)
412 char buf[64];
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);
416 return defv;
419 static void init_options()
421 if (!gdk_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)
441 if (!hwnd) return;
443 bool isVis = hwnd->m_oswindow != NULL;
444 bool wantVis = !hwnd->m_parent && hwnd->m_visible;
446 if (isVis != wantVis)
448 if (!wantVis)
450 RECT r;
451 GetWindowRect(hwnd,&r);
452 swell_oswindow_destroy(hwnd);
453 hwnd->m_position = r;
455 else
457 if (swell_initwindowsys())
459 init_options();
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;
474 attr.x = r.left;
475 attr.y = r.top;
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))
494 if (transient_for)
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);
499 else
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;
507 else
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);
515 if (transient_for)
517 gdk_window_set_transient_for(hwnd->m_oswindow,transient_for);
518 if (modal)
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;
536 #endif
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);
563 else
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);
573 else
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;
580 while (l)
582 if (!l->m_oswindow && l->m_owner == hwnd && l->m_visible)
583 swell_oswindow_manage(l,false);
584 l = l->m_next;
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);
608 cairo_paint(crc);
609 cairo_destroy(crc);
611 gdk_window_end_paint(hwnd->m_oswindow);
613 if (temp_surface) bm->Extended(0xca140,temp_surface); // release
616 #endif
619 #if SWELL_TARGET_GDK == 2
620 #define DEF_GKY(x) GDK_##x
621 #else
622 #define DEF_GKY(x) GDK_KEY_##x
623 #endif
625 static guint swell_gdkConvertKey(guint key)
627 //gdk key to VK_ conversion
628 switch(key)
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;
634 case DEF_GKY(KP_Up):
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;
686 return 0;
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);
700 return -1;
703 LRESULT htc=0;
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));
742 return ret;
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';
750 return -1;
753 static GdkAtom utf8atom()
755 static GdkAtom tmp;
756 if (!tmp) tmp = gdk_atom_intern_static_string("UTF8_STRING");
757 return tmp;
759 static GdkAtom tgtatom()
761 static GdkAtom tmp;
762 if (!tmp) tmp = gdk_atom_intern_static_string("TARGETS");
763 return tmp;
765 static GdkAtom urilistatom()
767 static GdkAtom tmp;
768 if (!tmp) tmp = gdk_atom_intern_static_string("text/uri-list");
769 return tmp;
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())
784 prop = b->property;
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);
789 #else
790 GdkWindow *pw = b->requestor;
791 #endif
792 if (pw)
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)
804 prop = b->property;
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);
809 #else
810 GdkWindow *pw = b->requestor;
811 #endif
812 if (pw)
813 gdk_property_change(pw,prop,GDK_SELECTION_TYPE_ATOM,32, GDK_PROP_MODE_REPLACE,(guchar*)list,(int) (sizeof(list)/sizeof(list[0])));
816 else
818 if (b->target == s_clipboard_setstate_fmt ||
819 (b->target == GDK_TARGET_STRING && s_clipboard_setstate_fmt == utf8atom())
822 prop = b->property;
823 int len = GlobalSize(s_clipboard_setstate);
824 guchar *ptr = (guchar*)s_clipboard_setstate;
826 WDL_FastString str;
827 if (s_clipboard_setstate_fmt == utf8atom())
829 const char *rd = (const char *)s_clipboard_setstate;
830 while (*rd)
832 if (!strncmp(rd,"\r\n",2))
834 str.Append("\n");
835 rd+=2;
837 else
838 str.Append(rd++,1);
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);
846 #else
847 GdkWindow *pw = b->requestor;
848 #endif
849 if (pw)
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);
860 if (!hwnd) return;
862 #ifdef SWELL_LICE_GDI
863 RECT r,cr;
865 // don't use GetClientRect(),since we're getting it pre-NCCALCSIZE etc
867 cr.left=cr.top=0;
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;
872 r.top=exp->area.y;
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);
895 cairo_paint(crc);
896 cairo_destroy(crc);
897 if (temp_surface) bm->Extended(0xca140,temp_surface); // release
899 gdk_window_end_paint(exp->window);
901 #endif
904 static void OnConfigureEvent(GdkEventConfigure *cfg)
906 HWND hwnd = swell_oswindow_to_hwnd(cfg->window);
907 if (!hwnd) return;
908 int flag=0;
909 if (cfg->x != hwnd->m_position.left ||
910 cfg->y != hwnd->m_position.top ||
911 !hwnd->m_has_had_position)
913 flag|=1;
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);
930 if (!hwnd) return;
932 int modifiers = 0;
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);
941 if (kv)
943 modifiers |= FVIRTKEY;
945 else
947 kv = k->keyval;
948 if (swell_is_virtkey_char(kv))
950 if (kv >= 'a' && kv <= 'z')
952 kv += 'A'-'a';
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;
961 else
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;
975 modifiers|=FVIRTKEY;
977 else if (kv > 255)
979 guint v = gdk_keyval_to_unicode(kv);
980 if (v) kv=v;
982 else
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);
1014 if (hwnd)
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);
1030 if (hwnd)
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;
1038 if (msg)
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);
1052 if (!hwnd) return;
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
1074 // win32 expects:
1075 // WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, WM_LBUTTONUP
1076 // what we send:
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
1080 // (one hopes)
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);
1101 if (!hwnd) return;
1103 if (hwnd == s_ddrop_hwnd && b->target == urilistatom())
1105 POINT p = s_ddrop_pt;
1106 HWND cw=hwnd;
1107 RECT r;
1108 GetWindowContentViewRect(hwnd,&r);
1109 if (PtInRect(&r,p))
1111 p.x -= r.left;
1112 p.y -= r.top;
1113 cw = ChildWindowFromPoint(hwnd,p);
1115 if (!cw) cw=hwnd;
1117 guchar *gptr=NULL;
1118 GdkAtom fmt;
1119 gint unitsz=0;
1120 gint sz=gdk_selection_property_get(b->window,&gptr,&fmt,&unitsz);
1122 if (sz>0 && gptr)
1124 HANDLE gobj=GlobalAlloc(0,sz+sizeof(DROPFILES));
1125 if (gobj)
1127 DROPFILES *df=(DROPFILES*)gobj;
1128 df->pFiles = sizeof(DROPFILES);
1129 df->pt = s_ddrop_pt;
1130 ScreenToClient(cw,&df->pt);
1131 df->fNC=FALSE;
1132 df->fWide=FALSE;
1133 guchar *pout = (guchar *)(df+1);
1134 const guchar *rd = gptr;
1135 const guchar *rd_end = rd + sz;
1136 for (;;)
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))
1143 rd += 7;
1144 int c=0;
1145 while (rd < rd_end && *rd && !isspace(*rd))
1147 int v1,v2;
1148 if (*rd == '%' && rd+2 < rd_end && (v1=hex_parse(rd[1]))>=0 && (v2=hex_parse(rd[2]))>=0)
1150 *pout++ = (v1<<4) | v2;
1151 rd+=3;
1153 else
1155 *pout++ = *rd++;
1157 c++;
1159 if (c) *pout++=0;
1161 else
1163 while (rd < rd_end && *rd && !isspace(*rd)) rd++;
1166 *pout++=0;
1167 *pout++=0;
1169 SendMessage(cw,WM_DROPFILES,(WPARAM)gobj,0);
1170 GlobalFree(gobj);
1174 if (gptr) g_free(gptr);
1175 s_ddrop_hwnd=NULL;
1176 return;
1179 s_ddrop_hwnd=NULL;
1181 if (s_clipboard_getstate) { GlobalFree(s_clipboard_getstate); s_clipboard_getstate=NULL; }
1182 guchar *gptr=NULL;
1183 GdkAtom fmt;
1184 gint unitsz=0;
1185 gint sz=gdk_selection_property_get(b->window,&gptr,&fmt,&unitsz);
1186 if (sz>0 && gptr && (unitsz == 8 || unitsz == 16 || unitsz == 32))
1188 WDL_FastString str;
1189 guchar *ptr = gptr;
1190 if (fmt == GDK_TARGET_STRING || fmt == utf8atom())
1192 int lastc=0;
1193 while (sz-->0)
1195 int c;
1196 if (unitsz==32) { c = *(unsigned int *)ptr; ptr+=4; }
1197 else if (unitsz==16) { c = *(unsigned short *)ptr; ptr+=2; }
1198 else c = *ptr++;
1200 if (!c) break;
1202 if (c == '\n' && lastc != '\r') str.Append("\r",1);
1204 char bv[8];
1205 if (fmt != GDK_TARGET_STRING)
1207 bv[0] = (char) ((unsigned char)c);
1208 str.Append(bv,1);
1210 else
1212 WDL_MakeUTFChar(bv,c,sizeof(bv));
1213 str.Append(bv);
1216 lastc=c;
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);
1236 if (!hwnd) return;
1238 GdkDragContext *ctx = e->context;
1239 if (ctx)
1241 POINT p = { (int)e->x_root, (int)e->y_root };
1242 s_ddrop_hwnd = hwnd;
1243 s_ddrop_pt = p;
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)
1253 while (w)
1255 HWND hwnd = swell_oswindow_to_hwnd(w);
1256 if (hwnd) return true;
1257 w = gdk_window_get_effective_parent(w);
1259 return false;
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))
1270 on_deactivate();
1274 static void swell_gdkEventHandler(GdkEvent *evt, gpointer data)
1276 GdkEvent *oldEvt = s_cur_evt;
1277 s_cur_evt = evt;
1279 switch (evt->type)
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)
1295 on_activate(0);
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))
1303 on_deactivate();
1305 else
1307 s_deactivate_timer = SetTimer(NULL,0,200,deactivateTimer);
1308 DestroyPopupMenus();
1312 break;
1313 case GDK_SELECTION_REQUEST:
1314 OnSelectionRequestEvent((GdkEventSelection *)evt);
1315 break;
1317 case GDK_DELETE:
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);
1323 break;
1324 case GDK_EXPOSE: // paint! GdkEventExpose...
1325 OnExposeEvent((GdkEventExpose *)evt);
1326 break;
1327 case GDK_CONFIGURE: // size/move, GdkEventConfigure
1328 OnConfigureEvent((GdkEventConfigure*)evt);
1329 break;
1330 case GDK_WINDOW_STATE: /// GdkEventWindowState for min/max
1331 //printf("minmax\n");
1332 break;
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;
1342 break;
1343 case GDK_KEY_PRESS:
1344 case GDK_KEY_RELEASE:
1345 swell_dlg_destroyspare();
1346 OnKeyEvent((GdkEventKey *)evt);
1347 break;
1348 #ifdef GDK_AVAILABLE_IN_3_4
1349 case GDK_TOUCH_BEGIN:
1350 case GDK_TOUCH_UPDATE:
1351 case GDK_TOUCH_END:
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;
1371 break;
1374 if (e->type == GDK_TOUCH_UPDATE)
1376 GdkEventMotion m;
1377 memset(&m,0,sizeof(m));
1378 m.type = GDK_MOTION_NOTIFY;
1379 m.window = e->window;
1380 m.time = e->time;
1381 m.x = e->x;
1382 m.y = e->y;
1383 m.axes = e->axes;
1384 m.state = e->state;
1385 m.device = e->device;
1386 m.x_root = e->x_root;
1387 m.y_root = e->y_root;
1388 OnMotionEvent(&m);
1390 else
1392 GdkEventButton but;
1393 memset(&but,0,sizeof(but));
1394 if (e->type == GDK_TOUCH_BEGIN)
1396 but.type = doubletap ? GDK_2BUTTON_PRESS:GDK_BUTTON_PRESS;
1398 else
1400 but.type = GDK_BUTTON_RELEASE;
1401 g_swell_touchptr = NULL;
1403 but.window = e->window;
1404 but.time = e->time;
1405 but.x = e->x;
1406 but.y = e->y;
1407 but.axes = e->axes;
1408 but.state = e->state;
1409 but.device = e->device;
1410 but.button = 1;
1411 but.x_root = e->x_root;
1412 but.y_root = e->y_root;
1413 swell_dlg_destroyspare();
1414 OnButtonEvent(&but);
1417 break;
1418 #endif
1419 case GDK_MOTION_NOTIFY:
1420 gdk_event_request_motions((GdkEventMotion *)evt);
1421 OnMotionEvent((GdkEventMotion *)evt);
1422 break;
1423 case GDK_SCROLL:
1424 OnScrollEvent((GdkEventScroll*)evt);
1425 break;
1426 case GDK_BUTTON_PRESS:
1427 case GDK_2BUTTON_PRESS:
1428 case GDK_BUTTON_RELEASE:
1429 swell_dlg_destroyspare();
1430 OnButtonEvent((GdkEventButton*)evt);
1431 break;
1432 case GDK_SELECTION_NOTIFY:
1433 OnSelectionNotifyEvent((GdkEventSelection *)evt);
1434 break;
1435 case GDK_DRAG_ENTER:
1436 case GDK_DRAG_MOTION:
1437 if (swell_oswindow_to_hwnd(((GdkEventAny*)evt)->window))
1439 GdkEventDND *e = (GdkEventDND *)evt;
1440 if (e->context)
1442 gdk_drag_status(e->context,GDK_ACTION_COPY,e->time);
1443 //? gdk_drop_reply(e->context,TRUE,e->time);
1446 break;
1447 case GDK_DRAG_LEAVE:
1448 case GDK_DRAG_STATUS:
1449 case GDK_DROP_FINISHED:
1450 break;
1451 case GDK_DROP_START:
1452 OnDropStartEvent((GdkEventDND *)evt);
1453 break;
1455 default:
1456 //printf("msg: %d\n",evt->type);
1457 break;
1459 #ifdef SWELL_SUPPORT_GTK
1460 gtk_main_do_event(evt);
1461 #endif
1462 s_cur_evt = oldEvt;
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();
1473 #else
1475 #if SWELL_TARGET_GDK == 2
1476 gdk_window_process_all_updates();
1477 #endif
1479 GMainContext *ctx=g_main_context_default();
1480 while (g_main_context_iteration(ctx,FALSE))
1482 GdkEvent *evt;
1483 while (gdk_events_pending() && (evt = gdk_event_get()))
1485 swell_gdkEventHandler(evt,(gpointer)1);
1486 gdk_event_free(evt);
1489 #endif
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));
1503 else
1504 gdk_window_set_decorations(hwnd->m_oswindow,(GdkWMDecoration) (GDK_DECOR_BORDER|GDK_DECOR_TITLE|GDK_DECOR_MINIMIZE));
1506 else
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)
1522 int rv=0;
1523 if (hwnd)
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);
1529 return rv;
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;
1546 return;
1548 r->left=r->top=0;
1549 r->right=1024;
1550 r->bottom=768;
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);
1564 r->left=x;
1565 r->top=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;
1568 return true;
1571 r->left=r->top=0;
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;
1575 return true;
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
1605 if (hwnd)
1607 while (hwnd && !hwnd->m_oswindow) hwnd=hwnd->m_parent;
1608 if (hwnd && hwnd->m_oswindow) gdk_window_process_updates(hwnd->m_oswindow,true);
1610 #endif
1613 void swell_oswindow_invalidate(HWND hwnd, const RECT *r)
1615 GdkRectangle gdkr;
1616 if (r)
1618 gdkr.x = r->left;
1619 gdkr.y = r->top;
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;
1639 return true;
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();
1660 for (;;)
1662 while (!s_clipboard_getstate && g_main_context_iteration(ctx,FALSE))
1664 GdkEvent *evt;
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;
1676 return NULL;
1679 DWORD now = GetTickCount();
1680 if (now < startt-1000 || now > startt+500) break;
1681 Sleep(10);
1684 return NULL;
1687 void CloseClipboard()
1689 s_clip_hwnd=NULL;
1692 UINT EnumClipboardFormats(UINT lastfmt)
1694 if (!lastfmt)
1696 // checking this causes issues (reentrancy, I suppose?)
1697 //if (req_clipboard(utf8atom()))
1698 return CF_TEXT;
1700 if (lastfmt == CF_TEXT) lastfmt = 0;
1702 int x=0;
1703 for (;;)
1705 int fmt=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;
1735 if (!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);
1744 if (w)
1746 s_clipboard_setstate_fmt = utf8atom();
1747 s_clipboard_setstate = h;
1748 gdk_selection_owner_set(w,GDK_SELECTION_CLIPBOARD,GDK_CURRENT_TIME,TRUE);
1750 return;
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;
1759 int x;
1760 const int n = m_clip_curfmts.GetSize();
1761 for(x=0;x<n;x++)
1762 if (!strcmp(m_clip_curfmts.Get(x),desc)) return x + 1;
1763 m_clip_curfmts.Add(strdup(desc));
1764 return n+1;
1768 void GetCursorPos(POINT *pt)
1770 pt->x=0;
1771 pt->y=0;
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);
1779 //#else
1780 gdk_display_get_pointer(gdk_display_get_default(),NULL,&pt->x,&pt->y,NULL);
1781 //#endif
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);
1798 //#else
1799 gdk_window_get_pointer(h? h->m_oswindow : gdk_get_default_root_window(),NULL,NULL,&mod);
1800 //#endif
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;
1811 return 0;
1814 DWORD GetMessagePos()
1816 return swell_lastMessagePos;
1819 struct bridgeState {
1820 bridgeState(bool needrep, GdkWindow *_w, Window _nw, Display *_disp);
1821 ~bridgeState();
1824 GdkWindow *w;
1825 Window native_w;
1826 Display *native_disp;
1828 bool lastvis;
1829 bool need_reparent;
1830 RECT lastrect;
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)
1841 w=_w;
1842 native_w=_nw;
1843 native_disp=_disp;
1844 lastvis=false;
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)
1852 switch (uMsg)
1854 case WM_DESTROY:
1855 if (hwnd && hwnd->m_private_data)
1857 bridgeState *bs = (bridgeState*)hwnd->m_private_data;
1858 hwnd->m_private_data = 0;
1859 delete bs;
1861 break;
1862 case WM_TIMER:
1863 if (wParam != 1) break;
1864 case WM_MOVE:
1865 case WM_SIZE:
1866 if (hwnd && hwnd->m_private_data)
1868 bridgeState *bs = (bridgeState*)hwnd->m_private_data;
1869 if (bs->w)
1871 HWND h = hwnd->m_parent;
1872 RECT tr = hwnd->m_position;
1873 while (h)
1875 RECT cr = h->m_position;
1876 if (h->m_oswindow)
1878 cr.right -= cr.left;
1879 cr.bottom -= cr.top;
1880 cr.left=cr.top=0;
1883 if (h->m_wndproc)
1885 NCCALCSIZE_PARAMS p = {{ cr }};
1886 h->m_wndproc(h,WM_NCCALCSIZE,0,(LPARAM)&p);
1887 cr = p.rgrc[0];
1889 tr.left += cr.left;
1890 tr.top += cr.top;
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;
1900 h=h->m_parent;
1903 // todo: need to periodically check to see if the plug-in has resized its window
1904 bool vis = IsWindowVisible(hwnd);
1905 if (vis)
1907 #if SWELL_TARGET_GDK == 2
1908 gint w=0,hh=0,d=0;
1909 gdk_window_get_geometry(bs->w,NULL,NULL,&w,&hh,&d);
1910 #else
1911 gint w=0,hh=0;
1912 gdk_window_get_geometry(bs->w,NULL,NULL,&w,&hh);
1913 #endif
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);
1938 bs->lastrect=tr;
1940 bs->need_reparent=false;
1942 else if (memcmp(&tr,&bs->lastrect,sizeof(RECT)))
1944 bs->lastrect = tr;
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);
1951 bs->lastvis = true;
1956 break;
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)
1971 //gint w=0,hh=0;
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)
1984 HWND hwnd = NULL;
1985 *wref = NULL;
1987 GdkWindow *ospar = NULL;
1988 HWND hpar = viewpar;
1989 while (hpar)
1991 ospar = hpar->m_oswindow;
1992 if (ospar) break;
1993 hpar = hpar->m_parent;
1996 bool need_reparent=false;
1998 if (!ospar)
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;
2011 if (gdkw)
2013 *wref = (void *) w;
2015 XSelectInput(disp, w, StructureNotifyMask | SubstructureNotifyMask);
2017 static bool filt_add;
2018 if (!filt_add)
2020 filt_add=true;
2021 gdk_window_add_filter(NULL, filterCreateShowProc, NULL);
2023 SetTimer(hwnd,1,100,NULL);
2024 if (!need_reparent) SendMessage(hwnd,WM_SIZE,0,0);
2026 return hwnd;
2029 struct dropSourceInfo {
2030 dropSourceInfo()
2032 srclist=NULL; srccount=0; srcfn=NULL; callback=NULL;
2033 state=0;
2034 dragctx=NULL;
2036 ~dropSourceInfo()
2038 free(srcfn);
2039 if (dragctx)
2041 if (_gdk_drag_drop_done) _gdk_drag_drop_done(dragctx,state!=0);
2042 g_object_unref(dragctx);
2046 const char **srclist;
2047 int srccount;
2048 // or
2049 void (*callback)(const char *);
2050 char *srcfn;
2052 int state;
2054 GdkDragContext *dragctx;
2057 static void encode_uri(WDL_FastString *s, const char *rd)
2059 while (*rd)
2061 // unsure if UTF-8 chars should be urlencoded or allowed?
2062 if (*rd < 0 || (!isalnum(*rd) && *rd != '-' && *rd != '_' && *rd != '.' && *rd != '/'))
2064 char buf[8];
2065 snprintf(buf,sizeof(buf),"%%%02x",(int)(unsigned char)*rd);
2066 s->Append(buf);
2068 else s->Append(rd,1);
2070 rd++;
2075 static LRESULT WINAPI dropSourceWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2077 dropSourceInfo *inf = (dropSourceInfo*)hwnd->m_private_data;
2078 switch (msg)
2080 case WM_CREATE:
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()));
2094 SetCapture(hwnd);
2095 break;
2096 case WM_MOUSEMOVE:
2097 if (inf->dragctx)
2099 POINT p;
2100 GetCursorPos(&p);
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)
2106 if (w)
2108 gdk_drag_motion(inf->dragctx,w,proto,p.x,p.y,GDK_ACTION_COPY,GDK_ACTION_COPY,GDK_CURRENT_TIME);
2111 break;
2112 case WM_LBUTTONUP:
2113 if (inf->dragctx && !inf->state)
2115 inf->state=1;
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);
2119 if (!sel)
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;
2125 return 0;
2127 ReleaseCapture();
2128 break;
2129 case WM_USER+100:
2130 if (wParam && lParam)
2132 GdkAtom *aOut = (GdkAtom *)lParam;
2133 GdkEventSelection *evt = (GdkEventSelection*)wParam;
2135 if (evt->target == urilistatom())
2137 WDL_FastString s;
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);
2154 if (s.GetLength())
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);
2160 #else
2161 GdkWindow *pw = evt->requestor;
2162 #endif
2163 if (pw)
2164 gdk_property_change(pw,*aOut,evt->target,8, GDK_PROP_MODE_REPLACE,(guchar*)s.Get(),s.GetLength());
2168 if (inf->state) ReleaseCapture();
2170 break;
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;
2182 RECT r={0,};
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)
2190 SWELL_RunEvents();
2191 Sleep(10);
2192 if (swell_dragsrc_timeout && GetTickCount()>swell_dragsrc_timeout) ReleaseCapture();
2195 swell_dragsrc_hwnd=NULL;
2196 DestroyWindow(h);
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;
2205 RECT r={0,};
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)
2213 SWELL_RunEvents();
2214 Sleep(10);
2215 if (swell_dragsrc_timeout && GetTickCount()>swell_dragsrc_timeout) ReleaseCapture();
2218 swell_dragsrc_hwnd=NULL;
2219 DestroyWindow(h);
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
2241 if (GetCapture())
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)
2250 #else
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)
2253 #endif
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
2259 #else
2260 gint devid = gdk_x11_device_get_id(dev);
2261 #endif
2262 if (disp && wn)
2264 if (curs)
2265 XIDefineCursor(disp,devid,wn, gdk_x11_cursor_get_xcursor((GdkCursor*)curs));
2266 else
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)
2289 gint x1, y1;
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);
2293 #else
2294 gdk_display_get_pointer(gdk_display_get_default(), NULL, &x1, &y1, NULL);
2295 #endif
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);
2312 #else
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);
2314 #endif
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(),
2327 X, Y);
2328 #else
2329 gdk_display_warp_pointer(gdk_display_get_default(),gdk_screen_get_default(), X, Y);
2330 #endif
2331 return true;
2334 static void getHotSpotForFile(const char *fn, POINT *pt)
2336 FILE *fp = fopen(fn,"rb");
2337 if (!fp) return;
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)
2341 fread(buf,1,16,fp);
2342 pt->x = buf[4]|(buf[5]<<8);
2343 pt->y = buf[6]|(buf[7]<<8);
2345 fclose(fp);
2348 HCURSOR SWELL_LoadCursorFromFile(const char *fn)
2350 GdkPixbuf *pb = gdk_pixbuf_new_from_file(fn,NULL);
2351 if (pb)
2353 POINT hs = {0,};
2354 getHotSpotForFile(fn,&hs);
2355 GdkCursor *curs = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),pb,hs.x,hs.y);
2356 g_object_unref(pb);
2357 return (HCURSOR) curs;
2359 return NULL;
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;
2375 else
2377 SWELL_CursorResourceIndex *p = SWELL_curmodule_cursorresource_head;
2378 while (p)
2380 if (p->resid == _idx)
2382 if (p->cachedCursor) return p->cachedCursor;
2383 // todo: load from p->resname, into p->cachedCursor, p->hotspot
2384 char buf[1024];
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);
2389 if (pb)
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);
2396 p=p->_next;
2400 HCURSOR hc= (HCURSOR)gdk_cursor_new_for_display(gdk_display_get_default(),def);
2402 return hc;
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;
2410 ri->resname=name;
2411 ri->cachedCursor=0;
2412 ri->resid = idx;
2413 ri->_next = SWELL_curmodule_cursorresource_head;
2414 SWELL_curmodule_cursorresource_head = ri;
2417 int SWELL_KeyToASCII(int wParam, int lParam, int *newflags)
2419 return 0;
2423 #endif
2424 #endif