pidgin/win32/gtkwin32dep.c

changeset 15435
4b933b06d75e
parent 15409
37b46bbce4cb
child 15562
8c8249fe5e3c
equal deleted inserted replaced
15434:94dcf9e39d66 15435:4b933b06d75e
1 /*
2 * gaim
3 *
4 * File: gtkwin32dep.c
5 * Date: June, 2002
6 * Description: Windows dependant code for Gaim
7 *
8 * Copyright (C) 2002-2003, Herman Bloggs <hermanator12002@yahoo.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25 #define _WIN32_IE 0x500
26 #ifndef WINVER
27 #define WINVER 0x0500 /* W2K */
28 #endif
29 #include <windows.h>
30 #include <io.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <winuser.h>
34
35 #include <glib.h>
36 #include <glib/gstdio.h>
37 #include <gtk/gtk.h>
38 #include <gdk/gdkwin32.h>
39
40 #include "debug.h"
41 #include "notify.h"
42
43 #include "resource.h"
44 #include "idletrack.h"
45 #include "zlib.h"
46 #include "untar.h"
47
48 #include <libintl.h>
49
50 #include "gtkwin32dep.h"
51 #include "win32dep.h"
52 #include "gtkconv.h"
53 #include "wspell.h"
54
55 /*
56 * GLOBALS
57 */
58 HINSTANCE gaimexe_hInstance = 0;
59 HINSTANCE gtkgaimdll_hInstance = 0;
60 HWND messagewin_hwnd;
61 static int gtkwin32_handle;
62
63 typedef BOOL (CALLBACK* LPFNFLASHWINDOWEX)(PFLASHWINFO);
64 static LPFNFLASHWINDOWEX MyFlashWindowEx = NULL;
65
66
67 /*
68 * PUBLIC CODE
69 */
70
71 HINSTANCE gtkwgaim_hinstance(void) {
72 return gaimexe_hInstance;
73 }
74
75 int gtkwgaim_gz_decompress(const char* in, const char* out) {
76 gzFile fin;
77 FILE *fout;
78 char buf[1024];
79 int ret;
80
81 if((fin = gzopen(in, "rb"))) {
82 if(!(fout = g_fopen(out, "wb"))) {
83 gaim_debug_error("gtkwgaim_gz_decompress", "Error opening file: %s\n", out);
84 gzclose(fin);
85 return 0;
86 }
87 }
88 else {
89 gaim_debug_error("gtkwgaim_gz_decompress", "gzopen failed to open: %s\n", in);
90 return 0;
91 }
92
93 while((ret = gzread(fin, buf, 1024))) {
94 if(fwrite(buf, 1, ret, fout) < ret) {
95 gaim_debug_error("wgaim_gz_decompress", "Error writing %d bytes to file\n", ret);
96 gzclose(fin);
97 fclose(fout);
98 return 0;
99 }
100 }
101 fclose(fout);
102 gzclose(fin);
103
104 if(ret < 0) {
105 gaim_debug_error("gtkwgaim_gz_decompress", "gzread failed while reading: %s\n", in);
106 return 0;
107 }
108
109 return 1;
110 }
111
112 int gtkwgaim_gz_untar(const char* filename, const char* destdir) {
113 char tmpfile[_MAX_PATH];
114 char template[]="wgaimXXXXXX";
115
116 sprintf(tmpfile, "%s%s%s", g_get_tmp_dir(), G_DIR_SEPARATOR_S, _mktemp(template));
117 if(gtkwgaim_gz_decompress(filename, tmpfile)) {
118 int ret;
119 if(untar(tmpfile, destdir, UNTAR_FORCE | UNTAR_QUIET))
120 ret = 1;
121 else {
122 gaim_debug_error("gtkwgaim_gz_untar", "Failure untarring %s\n", tmpfile);
123 ret = 0;
124 }
125 g_unlink(tmpfile);
126 return ret;
127 }
128 else {
129 gaim_debug_error("gtkwgaim_gz_untar", "Failed to gz decompress %s\n", filename);
130 return 0;
131 }
132 }
133
134 void gtkwgaim_shell_execute(const char *target, const char *verb, const char *clazz) {
135
136 g_return_if_fail(target != NULL);
137 g_return_if_fail(verb != NULL);
138
139 if (G_WIN32_HAVE_WIDECHAR_API()) {
140 SHELLEXECUTEINFOW wsinfo;
141 wchar_t *w_uri, *w_verb, *w_clazz = NULL;
142
143 w_uri = g_utf8_to_utf16(target, -1, NULL, NULL, NULL);
144 w_verb = g_utf8_to_utf16(verb, -1, NULL, NULL, NULL);
145
146 memset(&wsinfo, 0, sizeof(wsinfo));
147 wsinfo.cbSize = sizeof(wsinfo);
148 wsinfo.lpVerb = w_verb;
149 wsinfo.lpFile = w_uri;
150 wsinfo.nShow = SW_SHOWNORMAL;
151 if (clazz != NULL) {
152 w_clazz = g_utf8_to_utf16(clazz, -1, NULL, NULL, NULL);
153 wsinfo.fMask |= SEE_MASK_CLASSNAME;
154 wsinfo.lpClass = w_clazz;
155 }
156
157 if(!ShellExecuteExW(&wsinfo))
158 gaim_debug_error("gtkwgaim", "Error opening URI: %s error: %d\n",
159 target, (int) wsinfo.hInstApp);
160
161 g_free(w_uri);
162 g_free(w_verb);
163 g_free(w_clazz);
164 } else {
165 SHELLEXECUTEINFOA sinfo;
166 gchar *locale_uri;
167
168 locale_uri = g_locale_from_utf8(target, -1, NULL, NULL, NULL);
169
170 memset(&sinfo, 0, sizeof(sinfo));
171 sinfo.cbSize = sizeof(sinfo);
172 sinfo.lpVerb = verb;
173 sinfo.lpFile = locale_uri;
174 sinfo.nShow = SW_SHOWNORMAL;
175 if (clazz != NULL) {
176 sinfo.fMask |= SEE_MASK_CLASSNAME;
177 sinfo.lpClass = clazz;
178 }
179
180 if(!ShellExecuteExA(&sinfo))
181 gaim_debug_error("gtkwgaim", "Error opening URI: %s error: %d\n",
182 target, (int) sinfo.hInstApp);
183
184 g_free(locale_uri);
185 }
186
187 }
188
189 void gtkwgaim_notify_uri(const char *uri) {
190 /* We'll allow whatever URI schemes are supported by the
191 * default http browser.
192 */
193 gtkwgaim_shell_execute(uri, "open", "http");
194 }
195
196 #define WM_FOCUS_REQUEST (WM_APP + 13)
197
198 static LRESULT CALLBACK message_window_handler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
199
200 if (msg == WM_FOCUS_REQUEST) {
201 gaim_debug_info("gtkwgaim", "Got external Buddy List focus request.");
202 gaim_blist_set_visible(TRUE);
203 return TRUE;
204 }
205
206 return DefWindowProc(hwnd, msg, wparam, lparam);
207 }
208
209 static HWND wgaim_message_window_init(void) {
210 HWND win_hwnd;
211 WNDCLASSEX wcx;
212 LPCTSTR wname;
213
214 wname = TEXT("WingaimMsgWinCls");
215
216 wcx.cbSize = sizeof(wcx);
217 wcx.style = 0;
218 wcx.lpfnWndProc = message_window_handler;
219 wcx.cbClsExtra = 0;
220 wcx.cbWndExtra = 0;
221 wcx.hInstance = gtkwgaim_hinstance();
222 wcx.hIcon = NULL;
223 wcx.hCursor = NULL;
224 wcx.hbrBackground = NULL;
225 wcx.lpszMenuName = NULL;
226 wcx.lpszClassName = wname;
227 wcx.hIconSm = NULL;
228
229 RegisterClassEx(&wcx);
230
231 /* Create the window */
232 if(!(win_hwnd = CreateWindow(wname, TEXT("WingaimMsgWin"), 0, 0, 0, 0, 0,
233 NULL, NULL, gtkwgaim_hinstance(), 0))) {
234 gaim_debug_error("gtkwgaim",
235 "Unable to create message window.\n");
236 return NULL;
237 }
238
239 return win_hwnd;
240 }
241
242 static gboolean stop_flashing(GtkWidget *widget, GdkEventFocus *event, gpointer data) {
243 GtkWindow *window = data;
244 gtkwgaim_window_flash(window, FALSE);
245 return FALSE;
246 }
247
248 void
249 gtkwgaim_window_flash(GtkWindow *window, gboolean flash) {
250 GdkWindow * gdkwin;
251
252 g_return_if_fail(window != NULL);
253
254 gdkwin = GTK_WIDGET(window)->window;
255
256 g_return_if_fail(GDK_IS_WINDOW(gdkwin));
257 g_return_if_fail(GDK_WINDOW_TYPE(gdkwin) != GDK_WINDOW_CHILD);
258
259 if(GDK_WINDOW_DESTROYED(gdkwin))
260 return;
261
262 if(MyFlashWindowEx) {
263 FLASHWINFO info;
264
265 memset(&info, 0, sizeof(FLASHWINFO));
266 info.cbSize = sizeof(FLASHWINFO);
267 info.hwnd = GDK_WINDOW_HWND(gdkwin);
268 if (flash)
269 info.dwFlags = FLASHW_ALL | FLASHW_TIMERNOFG;
270 else
271 info.dwFlags = FLASHW_STOP;
272 info.dwTimeout = 0;
273 info.dwTimeout = 0;
274
275 MyFlashWindowEx(&info);
276 } else
277 FlashWindow(GDK_WINDOW_HWND(gdkwin), flash);
278 }
279
280 void
281 gtkwgaim_conv_blink(GaimConversation *conv, GaimMessageFlags flags) {
282 GaimGtkWindow *win;
283 GtkWindow *window;
284
285 /* Don't flash for our own messages or system messages */
286 if(flags & GAIM_MESSAGE_SEND || flags & GAIM_MESSAGE_SYSTEM)
287 return;
288
289 if(conv == NULL) {
290 gaim_debug_info("gtkwgaim", "No conversation found to blink.\n");
291 return;
292 }
293
294 win = gaim_gtkconv_get_window(GAIM_GTK_CONVERSATION(conv));
295 if(win == NULL) {
296 gaim_debug_info("gtkwgaim", "No conversation windows found to blink.\n");
297 return;
298 }
299 window = GTK_WINDOW(win->window);
300
301 gtkwgaim_window_flash(window, TRUE);
302 /* Stop flashing when window receives focus */
303 g_signal_connect(G_OBJECT(window), "focus-in-event",
304 G_CALLBACK(stop_flashing), window);
305 }
306
307 static gboolean
308 gtkwgaim_conv_im_blink(GaimAccount *account, const char *who, char **message,
309 GaimConversation *conv, GaimMessageFlags flags, void *data)
310 {
311 if (gaim_prefs_get_bool("/gaim/gtk/win32/blink_im"))
312 gtkwgaim_conv_blink(conv, flags);
313 return FALSE;
314 }
315
316 void gtkwgaim_init(HINSTANCE hint) {
317
318 gaim_debug_info("gtkwgaim", "gtkwgaim_init start\n");
319
320 gaimexe_hInstance = hint;
321
322 /* IdleTracker Initialization */
323 if(!wgaim_set_idlehooks())
324 gaim_debug_error("gtkwgaim", "Failed to initialize idle tracker\n");
325
326 wgaim_gtkspell_init();
327 gaim_debug_info("gtkwgaim", "GTK+ :%u.%u.%u\n",
328 gtk_major_version, gtk_minor_version, gtk_micro_version);
329
330 messagewin_hwnd = wgaim_message_window_init();
331
332 MyFlashWindowEx = (LPFNFLASHWINDOWEX) wgaim_find_and_loadproc("user32.dll", "FlashWindowEx");
333
334 gaim_debug_info("gtkwgaim", "gtkwgaim_init end\n");
335 }
336
337 void gtkwgaim_post_init(void) {
338
339 gaim_prefs_add_none("/gaim/gtk/win32");
340 gaim_prefs_add_bool("/gaim/gtk/win32/blink_im", TRUE);
341
342 gaim_signal_connect(gaim_gtk_conversations_get_handle(),
343 "displaying-im-msg", &gtkwin32_handle, GAIM_CALLBACK(gtkwgaim_conv_im_blink),
344 NULL);
345
346 }
347
348 /* Windows Cleanup */
349
350 void gtkwgaim_cleanup(void) {
351 gaim_debug_info("gtkwgaim", "gtkwgaim_cleanup\n");
352
353 if(messagewin_hwnd)
354 DestroyWindow(messagewin_hwnd);
355
356 /* Idle tracker cleanup */
357 wgaim_remove_idlehooks();
358
359 }
360
361 /* DLL initializer */
362 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
363 gtkgaimdll_hInstance = hinstDLL;
364 return TRUE;
365 }
366
367 typedef HMONITOR WINAPI gaim_MonitorFromWindow(HWND, DWORD);
368 typedef BOOL WINAPI gaim_GetMonitorInfo(HMONITOR, LPMONITORINFO);
369
370 static gboolean
371 get_WorkingAreaRectForWindow(HWND hwnd, RECT *workingAreaRc) {
372 static gaim_MonitorFromWindow *the_MonitorFromWindow;
373 static gaim_GetMonitorInfo *the_GetMonitorInfo;
374 static gboolean initialized = FALSE;
375
376 HMONITOR monitor;
377 MONITORINFO info;
378
379 if(!initialized) {
380 the_MonitorFromWindow = (gaim_MonitorFromWindow*)
381 wgaim_find_and_loadproc("user32", "MonitorFromWindow");
382 the_GetMonitorInfo = (gaim_GetMonitorInfo*)
383 wgaim_find_and_loadproc("user32", "GetMonitorInfoA");
384 initialized = TRUE;
385 }
386
387 if(!the_MonitorFromWindow)
388 return FALSE;
389
390 if(!the_GetMonitorInfo)
391 return FALSE;
392
393 monitor = the_MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
394
395 info.cbSize = sizeof(info);
396 if(!the_GetMonitorInfo(monitor, &info))
397 return FALSE;
398
399 CopyRect(workingAreaRc, &(info.rcWork));
400 return TRUE;
401 }
402
403 void gtkwgaim_ensure_onscreen(GtkWidget *win) {
404 RECT windowRect, workingAreaRect, intersectionRect;
405 HWND hwnd = GDK_WINDOW_HWND(win->window);
406
407 g_return_if_fail(hwnd != NULL);
408 GetWindowRect(hwnd, &windowRect);
409
410 gaim_debug_info("win32placement",
411 "Window RECT: L:%ld R:%ld T:%ld B:%ld\n",
412 windowRect.left, windowRect.right,
413 windowRect.top, windowRect.bottom);
414
415 if(!get_WorkingAreaRectForWindow(hwnd, &workingAreaRect)) {
416 gaim_debug_info("win32placement",
417 "Couldn't get multimonitor working area\n");
418 if(!SystemParametersInfo(SPI_GETWORKAREA, 0, &workingAreaRect, FALSE)) {
419 /* I don't think this will ever happen */
420 workingAreaRect.left = 0;
421 workingAreaRect.top = 0;
422 workingAreaRect.bottom = GetSystemMetrics(SM_CYSCREEN);
423 workingAreaRect.right = GetSystemMetrics(SM_CXSCREEN);
424 }
425 }
426
427 gaim_debug_info("win32placement",
428 "Working Area RECT: L:%ld R:%ld T:%ld B:%ld\n",
429 workingAreaRect.left, workingAreaRect.right,
430 workingAreaRect.top, workingAreaRect.bottom);
431
432 /** If the conversation window doesn't intersect perfectly with the working area,
433 * move it to the top left corner of the working area */
434 if(!(IntersectRect(&intersectionRect, &windowRect, &workingAreaRect)
435 && EqualRect(&intersectionRect, &windowRect))) {
436 gaim_debug_info("win32placement",
437 "conversation window out of working area, relocating\n");
438 MoveWindow(hwnd, workingAreaRect.left, workingAreaRect.top,
439 (windowRect.right - windowRect.left),
440 (windowRect.bottom - windowRect.top), TRUE);
441 }
442 }
443

mercurial