~ubuntu-branches/ubuntu/jaunty/fltk1.1/jaunty

« back to all changes in this revision

Viewing changes to src/Fl_win32.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Aaron M. Ucko
  • Date: 2004-04-14 21:55:19 UTC
  • Revision ID: james.westby@ubuntu.com-20040414215519-avj0ojjkjni1s4ty
Tags: upstream-1.1.4+1.1.5rc1
ImportĀ upstreamĀ versionĀ 1.1.4+1.1.5rc1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// "$Id: Fl_win32.cxx,v 1.33.2.37.2.48 2004/04/11 04:38:59 easysw Exp $"
 
3
//
 
4
// WIN32-specific code for the Fast Light Tool Kit (FLTK).
 
5
//
 
6
// Copyright 1998-2004 by Bill Spitzak and others.
 
7
//
 
8
// This library is free software; you can redistribute it and/or
 
9
// modify it under the terms of the GNU Library General Public
 
10
// License as published by the Free Software Foundation; either
 
11
// version 2 of the License, or (at your option) any later version.
 
12
//
 
13
// This library is distributed in the hope that it will be useful,
 
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
// Library General Public License for more details.
 
17
//
 
18
// You should have received a copy of the GNU Library General Public
 
19
// License along with this library; if not, write to the Free Software
 
20
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
21
// USA.
 
22
//
 
23
// Please report all bugs and problems to "fltk-bugs@fltk.org".
 
24
//
 
25
 
 
26
// This file contains win32-specific code for fltk which is always linked
 
27
// in.  Search other files for "WIN32" or filenames ending in _win32.cxx
 
28
// for other system-specific code.
 
29
 
 
30
#include <FL/Fl.H>
 
31
#include <FL/x.H>
 
32
#include <FL/Fl_Window.H>
 
33
#include "flstring.h"
 
34
#include <stdio.h>
 
35
#include <stdlib.h>
 
36
#include <sys/types.h>
 
37
#include <time.h>
 
38
#ifdef __CYGWIN__
 
39
#  include <sys/time.h>
 
40
#  include <unistd.h>
 
41
#else
 
42
#  include <winsock.h>
 
43
#endif
 
44
#include <winuser.h>
 
45
#include <commctrl.h>
 
46
 
 
47
// The following include files require GCC 3.x or a non-GNU compiler...
 
48
#if !defined(__GNUC__) || __GNUC__ >= 3
 
49
#  include <ole2.h>
 
50
#  include <ShellApi.h>
 
51
#endif // !__GNUC__ || __GNUC__ >= 3
 
52
 
 
53
 
 
54
//
 
55
// USE_ASYNC_SELECT - define it if you have WSAAsyncSelect()...
 
56
//
 
57
// This currently doesn't appear to work; needs to be fixed!
 
58
//
 
59
 
 
60
//#define USE_ASYNC_SELECT
 
61
 
 
62
 
 
63
//
 
64
// USE_TRACK_MOUSE - define it if you have TrackMouseEvent()...
 
65
//
 
66
// Apparently, at least some versions of Cygwin/MingW don't provide
 
67
// the TrackMouseEvent() function.  You can define this by hand
 
68
// if you have it - this is only needed to support subwindow
 
69
// enter/leave notification under Windows.
 
70
//
 
71
 
 
72
//#define USE_TRACK_MOUSE
 
73
 
 
74
#if !defined(__GNUC__)
 
75
#  define USE_TRACK_MOUSE
 
76
#endif // !__GNUC__
 
77
 
 
78
 
 
79
//
 
80
// WM_SYNCPAINT is an "undocumented" message, which is finally defined in
 
81
// VC++ 6.0.
 
82
//
 
83
 
 
84
#ifndef WM_SYNCPAINT
 
85
#  define WM_SYNCPAINT 0x0088
 
86
#endif
 
87
 
 
88
#ifndef WM_MOUSELEAVE
 
89
#  define WM_MOUSELEAVE 0x02a3
 
90
#endif
 
91
 
 
92
#ifndef WM_MOUSEWHEEL
 
93
#  define WM_MOUSEWHEEL 0x020a
 
94
#endif
 
95
 
 
96
#ifndef WHEEL_DELTA
 
97
#  define WHEEL_DELTA 120       // according to MSDN.
 
98
#endif
 
99
 
 
100
 
 
101
//
 
102
// WM_FLSELECT is the user-defined message that we get when one of
 
103
// the sockets has pending data, etc.
 
104
//
 
105
 
 
106
#define WM_FLSELECT     (WM_USER+0x0400)
 
107
 
 
108
 
 
109
////////////////////////////////////////////////////////////////
 
110
// interface to poll/select call:
 
111
 
 
112
// fd's are only implemented for sockets.  Microsoft Windows does not
 
113
// have a unified IO system, so it doesn't support select() on files,
 
114
// devices, or pipes...
 
115
//
 
116
// Microsoft provides the Berkeley select() call and an asynchronous
 
117
// select function that sends a WIN32 message when the select condition
 
118
// exists...
 
119
static int maxfd = 0;
 
120
#ifndef USE_ASYNC_SELECT
 
121
static fd_set fdsets[3];
 
122
#endif // !USE_ASYNC_SELECT
 
123
 
 
124
#define POLLIN 1
 
125
#define POLLOUT 4
 
126
#define POLLERR 8
 
127
 
 
128
#if !defined(__GNUC__) || __GNUC__ >= 3
 
129
extern IDropTarget *flIDropTarget;
 
130
#endif // !__GNUC__ || __GNUC__ >= 3
 
131
 
 
132
static int nfds = 0;
 
133
static int fd_array_size = 0;
 
134
static struct FD {
 
135
  int fd;
 
136
  short events;
 
137
  void (*cb)(int, void*);
 
138
  void* arg;
 
139
} *fd = 0;
 
140
 
 
141
void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) {
 
142
  remove_fd(n,events);
 
143
  int i = nfds++;
 
144
  if (i >= fd_array_size) {
 
145
    fd_array_size = 2*fd_array_size+1;
 
146
    fd = (FD*)realloc(fd, fd_array_size*sizeof(FD));
 
147
  }
 
148
  fd[i].fd = n;
 
149
  fd[i].events = (short)events;
 
150
  fd[i].cb = cb;
 
151
  fd[i].arg = v;
 
152
 
 
153
#ifdef USE_ASYNC_SELECT
 
154
  int mask = 0;
 
155
  if (events & POLLIN) mask |= FD_READ;
 
156
  if (events & POLLOUT) mask |= FD_WRITE;
 
157
  if (events & POLLERR) mask |= FD_CLOSE;
 
158
  WSAAsyncSelect(n, fl_window, WM_FLSELECT, mask);
 
159
#else
 
160
  if (events & POLLIN) FD_SET(n, &fdsets[0]);
 
161
  if (events & POLLOUT) FD_SET(n, &fdsets[1]);
 
162
  if (events & POLLERR) FD_SET(n, &fdsets[2]);
 
163
  if (n > maxfd) maxfd = n;
 
164
#endif // USE_ASYNC_SELECT
 
165
}
 
166
 
 
167
void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) {
 
168
  Fl::add_fd(fd, POLLIN, cb, v);
 
169
}
 
170
 
 
171
void Fl::remove_fd(int n, int events) {
 
172
  int i,j;
 
173
  for (i=j=0; i<nfds; i++) {
 
174
    if (fd[i].fd == n) {
 
175
      short e = fd[i].events & ~events;
 
176
      if (!e) continue; // if no events left, delete this fd
 
177
      fd[i].events = e;
 
178
    }
 
179
    // move it down in the array if necessary:
 
180
    if (j<i) {
 
181
      fd[j]=fd[i];
 
182
    }
 
183
    j++;
 
184
  }
 
185
  nfds = j;
 
186
 
 
187
#ifdef USE_ASYNC_SELECT
 
188
  WSAAsyncSelect(n, 0, 0, 0);
 
189
#else
 
190
  if (events & POLLIN) FD_CLR(unsigned(n), &fdsets[0]);
 
191
  if (events & POLLOUT) FD_CLR(unsigned(n), &fdsets[1]);
 
192
  if (events & POLLERR) FD_CLR(unsigned(n), &fdsets[2]);
 
193
#endif // USE_ASYNC_SELECT
 
194
}
 
195
 
 
196
void Fl::remove_fd(int n) {
 
197
  remove_fd(n, -1);
 
198
}
 
199
 
 
200
// these pointers are set by the Fl::lock() function:
 
201
static void nothing() {}
 
202
void (*fl_lock_function)() = nothing;
 
203
void (*fl_unlock_function)() = nothing;
 
204
 
 
205
static void* thread_message_;
 
206
void* Fl::thread_message() {
 
207
  void* r = thread_message_;
 
208
  thread_message_ = 0;
 
209
  return r;
 
210
}
 
211
 
 
212
MSG fl_msg;
 
213
 
 
214
// This is never called with time_to_wait < 0.0.
 
215
// It *should* return negative on error, 0 if nothing happens before
 
216
// timeout, and >0 if any callbacks were done.  This version only
 
217
// returns zero if nothing happens during a 0.0 timeout, otherwise
 
218
// it returns 1.
 
219
int fl_wait(double time_to_wait) {
 
220
  int have_message = 0;
 
221
  int timerid;
 
222
 
 
223
#ifndef USE_ASYNC_SELECT
 
224
  if (nfds) {
 
225
    // For WIN32 we need to poll for socket input FIRST, since
 
226
    // the event queue is not something we can select() on...
 
227
    timeval t;
 
228
    t.tv_sec = 0;
 
229
    t.tv_usec = 0;
 
230
 
 
231
    fd_set fdt[3];
 
232
    fdt[0] = fdsets[0];
 
233
    fdt[1] = fdsets[1];
 
234
    fdt[2] = fdsets[2];
 
235
    if (::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t)) {
 
236
      // We got something - do the callback!
 
237
      for (int i = 0; i < nfds; i ++) {
 
238
        int f = fd[i].fd;
 
239
        short revents = 0;
 
240
        if (FD_ISSET(f,&fdt[0])) revents |= POLLIN;
 
241
        if (FD_ISSET(f,&fdt[1])) revents |= POLLOUT;
 
242
        if (FD_ISSET(f,&fdt[2])) revents |= POLLERR;
 
243
        if (fd[i].events & revents) fd[i].cb(f, fd[i].arg);
 
244
      }
 
245
      time_to_wait = 0.0; // just peek for any messages
 
246
#ifdef __CYGWIN__
 
247
    }
 
248
#else
 
249
    } else {
 
250
      // we need to check them periodically, so set a short timeout:
 
251
      if (time_to_wait > .001) time_to_wait = .001;
 
252
    }
 
253
#endif
 
254
  }
 
255
#endif // USE_ASYNC_SELECT
 
256
 
 
257
  fl_unlock_function();
 
258
 
 
259
  if (time_to_wait < 2147483.648) {
 
260
    // Perform the requested timeout...
 
261
    have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
 
262
    if (!have_message) {
 
263
      int t = (int)(time_to_wait * 1000.0 + .5);
 
264
      if (t <= 0) { // too short to measure
 
265
        fl_lock_function();
 
266
        return 0;
 
267
      }
 
268
      timerid = SetTimer(NULL, 0, t, NULL);
 
269
      have_message = GetMessage(&fl_msg, NULL, 0, 0);
 
270
      KillTimer(NULL, timerid);
 
271
    }
 
272
  } else {
 
273
    have_message = GetMessage(&fl_msg, NULL, 0, 0);
 
274
  }
 
275
 
 
276
  fl_lock_function();
 
277
 
 
278
  // Execute the message we got, and all other pending messages:
 
279
  while (have_message) {
 
280
#ifdef USE_ASYNC_SELECT
 
281
    if (fl_msg.message == WM_FLSELECT) {
 
282
      // Got notification for socket
 
283
      for (int i = 0; i < nfds; i ++)
 
284
        if (fd[i].fd == (int)fl_msg.wParam) {
 
285
          (fd[i].cb)(fd[i].fd, fd[i].arg);
 
286
          break;
 
287
        }
 
288
      // looks like it is best to do the dispatch-message anyway:
 
289
    }
 
290
#endif
 
291
 
 
292
    if (fl_msg.message == fl_wake_msg)  // Used for awaking wait() from another thread
 
293
      thread_message_ = (void*)fl_msg.wParam;
 
294
 
 
295
    TranslateMessage(&fl_msg);
 
296
    DispatchMessage(&fl_msg);
 
297
    have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
 
298
  }
 
299
 
 
300
  // This should return 0 if only timer events were handled:
 
301
  return 1;
 
302
}
 
303
 
 
304
// fl_ready() is just like fl_wait(0.0) except no callbacks are done:
 
305
int fl_ready() {
 
306
  if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) return 1;
 
307
#ifdef USE_ASYNC_SELECT
 
308
  return 0;
 
309
#else
 
310
  timeval t;
 
311
  t.tv_sec = 0;
 
312
  t.tv_usec = 0;
 
313
  fd_set fdt[3];
 
314
  fdt[0] = fdsets[0];
 
315
  fdt[1] = fdsets[1];
 
316
  fdt[2] = fdsets[2];
 
317
  return ::select(0,&fdt[0],&fdt[1],&fdt[2],&t);
 
318
#endif // USE_ASYNC_SELECT
 
319
}
 
320
 
 
321
////////////////////////////////////////////////////////////////
 
322
 
 
323
int Fl::x()
 
324
{
 
325
  RECT r;
 
326
 
 
327
  SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
 
328
  return r.left;
 
329
}
 
330
 
 
331
int Fl::y()
 
332
{
 
333
  RECT r;
 
334
 
 
335
  SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
 
336
  return r.top;
 
337
}
 
338
 
 
339
int Fl::h()
 
340
{
 
341
  RECT r;
 
342
 
 
343
  SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
 
344
  return r.bottom - r.top;
 
345
}
 
346
 
 
347
int Fl::w()
 
348
{
 
349
  RECT r;
 
350
 
 
351
  SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
 
352
  return r.right - r.left;
 
353
}
 
354
 
 
355
void Fl::get_mouse(int &x, int &y) {
 
356
  POINT p;
 
357
  GetCursorPos(&p);
 
358
  x = p.x;
 
359
  y = p.y;
 
360
}
 
361
 
 
362
////////////////////////////////////////////////////////////////
 
363
// code used for selections:
 
364
 
 
365
char *fl_selection_buffer[2];
 
366
int fl_selection_length[2];
 
367
int fl_selection_buffer_length[2];
 
368
char fl_i_own_selection[2];
 
369
 
 
370
// call this when you create a selection:
 
371
void Fl::copy(const char *stuff, int len, int clipboard) {
 
372
  if (!stuff || len<0) return;
 
373
  if (len+1 > fl_selection_buffer_length[clipboard]) {
 
374
    delete[] fl_selection_buffer[clipboard];
 
375
    fl_selection_buffer[clipboard] = new char[len+100];
 
376
    fl_selection_buffer_length[clipboard] = len+100;
 
377
  }
 
378
  memcpy(fl_selection_buffer[clipboard], stuff, len);
 
379
  fl_selection_buffer[clipboard][len] = 0; // needed for direct paste
 
380
  fl_selection_length[clipboard] = len;
 
381
  if (clipboard) {
 
382
    // set up for "delayed rendering":
 
383
    if (OpenClipboard(fl_xid(Fl::first_window()))) {
 
384
      EmptyClipboard();
 
385
      SetClipboardData(CF_TEXT, NULL);
 
386
      CloseClipboard();
 
387
    }
 
388
    fl_i_own_selection[clipboard] = 1;
 
389
  }
 
390
}
 
391
 
 
392
// Call this when a "paste" operation happens:
 
393
void Fl::paste(Fl_Widget &receiver, int clipboard) {
 
394
  if (!clipboard || fl_i_own_selection[clipboard]) {
 
395
    // We already have it, do it quickly without window server.
 
396
    // Notice that the text is clobbered if set_selection is
 
397
    // called in response to FL_PASTE!
 
398
    Fl::e_text = fl_selection_buffer[clipboard];
 
399
    Fl::e_length = fl_selection_length[clipboard];
 
400
 
 
401
    if (!Fl::e_text) Fl::e_text = (char *)"";
 
402
    receiver.handle(FL_PASTE);
 
403
  } else {
 
404
    if (!OpenClipboard(NULL)) return;
 
405
    HANDLE h = GetClipboardData(CF_TEXT);
 
406
    if (h) {
 
407
      Fl::e_text = (LPSTR)GlobalLock(h);
 
408
      LPSTR a,b;
 
409
      a = b = Fl::e_text;
 
410
      while (*a) { // strip the CRLF pairs ($%$#@^)
 
411
        if (*a == '\r' && a[1] == '\n') a++;
 
412
        else *b++ = *a++;
 
413
      }
 
414
      *b = 0;
 
415
      Fl::e_length = b - Fl::e_text;
 
416
      receiver.handle(FL_PASTE);
 
417
      GlobalUnlock(h);
 
418
    }
 
419
    CloseClipboard();
 
420
  }
 
421
}
 
422
 
 
423
////////////////////////////////////////////////////////////////
 
424
 
 
425
HWND fl_capture;
 
426
 
 
427
static int mouse_event(Fl_Window *window, int what, int button,
 
428
                        WPARAM wParam, LPARAM lParam)
 
429
{
 
430
  static int px, py, pmx, pmy;
 
431
  POINT pt;
 
432
  Fl::e_x = pt.x = (signed short)LOWORD(lParam);
 
433
  Fl::e_y = pt.y = (signed short)HIWORD(lParam);
 
434
  ClientToScreen(fl_xid(window), &pt);
 
435
  Fl::e_x_root = pt.x;
 
436
  Fl::e_y_root = pt.y;
 
437
  while (window->parent()) {
 
438
    Fl::e_x += window->x();
 
439
    Fl::e_y += window->y();
 
440
    window = window->window();
 
441
  }
 
442
 
 
443
  ulong state = Fl::e_state & 0xff0000; // keep shift key states
 
444
#if 0
 
445
  // mouse event reports some shift flags, perhaps save them?
 
446
  if (wParam & MK_SHIFT) state |= FL_SHIFT;
 
447
  if (wParam & MK_CONTROL) state |= FL_CTRL;
 
448
#endif
 
449
  if (wParam & MK_LBUTTON) state |= FL_BUTTON1;
 
450
  if (wParam & MK_MBUTTON) state |= FL_BUTTON2;
 
451
  if (wParam & MK_RBUTTON) state |= FL_BUTTON3;
 
452
  Fl::e_state = state;
 
453
 
 
454
  switch (what) {
 
455
  case 1: // double-click
 
456
    if (Fl::e_is_click) {Fl::e_clicks++; goto J1;}
 
457
  case 0: // single-click
 
458
    Fl::e_clicks = 0;
 
459
  J1:
 
460
    if (!fl_capture) SetCapture(fl_xid(window));
 
461
    Fl::e_keysym = FL_Button + button;
 
462
    Fl::e_is_click = 1;
 
463
    px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root;
 
464
    return Fl::handle(FL_PUSH,window);
 
465
 
 
466
  case 2: // release:
 
467
    if (!fl_capture) ReleaseCapture();
 
468
    Fl::e_keysym = FL_Button + button;
 
469
    return Fl::handle(FL_RELEASE,window);
 
470
 
 
471
  case 3: // move:
 
472
  default: // avoid compiler warning
 
473
    // MSWindows produces extra events even if mouse does not move, ignore em:
 
474
    if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1;
 
475
    pmx = Fl::e_x_root; pmy = Fl::e_y_root;
 
476
    if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0;
 
477
    return Fl::handle(FL_MOVE,window);
 
478
 
 
479
  }
 
480
}
 
481
 
 
482
// convert a MSWindows VK_x to an Fltk (X) Keysym:
 
483
// See also the inverse converter in Fl_get_key_win32.cxx
 
484
// This table is in numeric order by VK:
 
485
static const struct {unsigned short vk, fltk, extended;} vktab[] = {
 
486
  {VK_BACK,     FL_BackSpace},
 
487
  {VK_TAB,      FL_Tab},
 
488
  {VK_CLEAR,    FL_KP+'5',      0xff0b/*XK_Clear*/},
 
489
  {VK_RETURN,   FL_Enter,       FL_KP_Enter},
 
490
  {VK_SHIFT,    FL_Shift_L,     FL_Shift_R},
 
491
  {VK_CONTROL,  FL_Control_L,   FL_Control_R},
 
492
  {VK_MENU,     FL_Alt_L,       FL_Alt_R},
 
493
  {VK_PAUSE,    FL_Pause},
 
494
  {VK_CAPITAL,  FL_Caps_Lock},
 
495
  {VK_ESCAPE,   FL_Escape},
 
496
  {VK_SPACE,    ' '},
 
497
  {VK_PRIOR,    FL_KP+'9',      FL_Page_Up},
 
498
  {VK_NEXT,     FL_KP+'3',      FL_Page_Down},
 
499
  {VK_END,      FL_KP+'1',      FL_End},
 
500
  {VK_HOME,     FL_KP+'7',      FL_Home},
 
501
  {VK_LEFT,     FL_KP+'4',      FL_Left},
 
502
  {VK_UP,       FL_KP+'8',      FL_Up},
 
503
  {VK_RIGHT,    FL_KP+'6',      FL_Right},
 
504
  {VK_DOWN,     FL_KP+'2',      FL_Down},
 
505
  {VK_SNAPSHOT, FL_Print},      // does not work on NT
 
506
  {VK_INSERT,   FL_KP+'0',      FL_Insert},
 
507
  {VK_DELETE,   FL_KP+'.',      FL_Delete},
 
508
  {VK_LWIN,     FL_Meta_L},
 
509
  {VK_RWIN,     FL_Meta_R},
 
510
  {VK_APPS,     FL_Menu},
 
511
  {VK_MULTIPLY, FL_KP+'*'},
 
512
  {VK_ADD,      FL_KP+'+'},
 
513
  {VK_SUBTRACT, FL_KP+'-'},
 
514
  {VK_DECIMAL,  FL_KP+'.'},
 
515
  {VK_DIVIDE,   FL_KP+'/'},
 
516
  {VK_NUMLOCK,  FL_Num_Lock},
 
517
  {VK_SCROLL,   FL_Scroll_Lock},
 
518
  {0xba,        ';'},
 
519
  {0xbb,        '='},
 
520
  {0xbc,        ','},
 
521
  {0xbd,        '-'},
 
522
  {0xbe,        '.'},
 
523
  {0xbf,        '/'},
 
524
  {0xc0,        '`'},
 
525
  {0xdb,        '['},
 
526
  {0xdc,        '\\'},
 
527
  {0xdd,        ']'},
 
528
  {0xde,        '\''}
 
529
};
 
530
static int ms2fltk(int vk, int extended) {
 
531
  static unsigned short vklut[256];
 
532
  static unsigned short extendedlut[256];
 
533
  if (!vklut[1]) { // init the table
 
534
    unsigned int i;
 
535
    for (i = 0; i < 256; i++) vklut[i] = tolower(i);
 
536
    for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1));
 
537
    for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0);
 
538
    for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++) {
 
539
      vklut[vktab[i].vk] = vktab[i].fltk;
 
540
      extendedlut[vktab[i].vk] = vktab[i].extended;
 
541
    }
 
542
    for (i = 0; i < 256; i++) if (!extendedlut[i]) extendedlut[i] = vklut[i];
 
543
  }
 
544
  return extended ? extendedlut[vk] : vklut[vk];
 
545
}
 
546
 
 
547
#if USE_COLORMAP
 
548
extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx
 
549
#endif
 
550
 
 
551
static Fl_Window* resize_bug_fix;
 
552
 
 
553
extern void fl_save_pen(void);
 
554
extern void fl_restore_pen(void);
 
555
 
 
556
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 
557
{
 
558
  // Copy the message to fl_msg so add_handler code can see it, it is
 
559
  // already there if this is called by DispatchMessage, but not if
 
560
  // Windows calls this directly.
 
561
  fl_msg.hwnd = hWnd;
 
562
  fl_msg.message = uMsg;
 
563
  fl_msg.wParam = wParam;
 
564
  fl_msg.lParam = lParam;
 
565
  //fl_msg.time = ???
 
566
  //fl_msg.pt = ???
 
567
  //fl_msg.lPrivate = ???
 
568
 
 
569
  Fl_Window *window = fl_find(hWnd);
 
570
 
 
571
  if (window) switch (uMsg) {
 
572
 
 
573
  case WM_QUIT: // this should not happen?
 
574
    Fl::fatal("WM_QUIT message");
 
575
 
 
576
  case WM_CLOSE: // user clicked close box
 
577
    Fl::handle(FL_CLOSE, window);
 
578
    return 0;
 
579
 
 
580
  case WM_SYNCPAINT :
 
581
  case WM_NCPAINT :
 
582
  case WM_ERASEBKGND :
 
583
    // Andreas Weitl - WM_SYNCPAINT needs to be passed to DefWindowProc
 
584
    // so that Windows can generate the proper paint messages...
 
585
    // Similarly, WM_NCPAINT and WM_ERASEBKGND need this, too...
 
586
    break;
 
587
 
 
588
  case WM_PAINT: {
 
589
    Fl_Region R;
 
590
    Fl_X *i = Fl_X::i(window);
 
591
    i->wait_for_expose = 0;
 
592
    if (!i->region && window->damage()) {
 
593
      // Redraw the whole window...
 
594
      i->region = CreateRectRgn(0, 0, window->w(), window->h());
 
595
    } else {
 
596
      // We need to merge WIN32's damage into FLTK's damage.
 
597
      R = CreateRectRgn(0,0,0,0);
 
598
      GetUpdateRgn(hWnd,R,0);
 
599
 
 
600
      if (i->region) {
 
601
        // Also tell WIN32 that we are drawing someplace else as well...
 
602
        InvalidateRgn(hWnd, i->region, FALSE);
 
603
        CombineRgn(i->region, i->region, R, RGN_OR);
 
604
        XDestroyRegion(R);
 
605
      } else {
 
606
        i->region = R;
 
607
      }
 
608
    }
 
609
    window->clear_damage((uchar)(window->damage()|FL_DAMAGE_EXPOSE));
 
610
    // These next two statements should not be here, so that all update
 
611
    // is deferred until Fl::flush() is called during idle.  However WIN32
 
612
    // apparently is very unhappy if we don't obey it and draw right now.
 
613
    // Very annoying!
 
614
    fl_GetDC(hWnd); // Make sure we have a DC for this window...
 
615
    fl_save_pen();
 
616
    i->flush();
 
617
    fl_restore_pen();
 
618
    if (window->type() == FL_DOUBLE_WINDOW) ValidateRgn(hWnd,0);
 
619
    else ValidateRgn(hWnd,i->region);
 
620
    window->clear_damage();
 
621
    } return 0;
 
622
 
 
623
  case WM_LBUTTONDOWN:  mouse_event(window, 0, 1, wParam, lParam); return 0;
 
624
  case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0;
 
625
  case WM_LBUTTONUP:    mouse_event(window, 2, 1, wParam, lParam); return 0;
 
626
  case WM_MBUTTONDOWN:  mouse_event(window, 0, 2, wParam, lParam); return 0;
 
627
  case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0;
 
628
  case WM_MBUTTONUP:    mouse_event(window, 2, 2, wParam, lParam); return 0;
 
629
  case WM_RBUTTONDOWN:  mouse_event(window, 0, 3, wParam, lParam); return 0;
 
630
  case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0;
 
631
  case WM_RBUTTONUP:    mouse_event(window, 2, 3, wParam, lParam); return 0;
 
632
 
 
633
  case WM_MOUSEMOVE:
 
634
#ifdef USE_TRACK_MOUSE
 
635
    if (Fl::belowmouse() != window) {
 
636
      TRACKMOUSEEVENT tme;
 
637
      tme.cbSize    = sizeof(TRACKMOUSEEVENT);
 
638
      tme.dwFlags   = TME_LEAVE;
 
639
      tme.hwndTrack = hWnd;
 
640
      _TrackMouseEvent(&tme);
 
641
    }
 
642
#endif // USE_TRACK_MOUSE
 
643
    mouse_event(window, 3, 0, wParam, lParam);
 
644
    return 0;
 
645
 
 
646
  case WM_MOUSELEAVE:
 
647
    Fl::belowmouse(0);
 
648
    if (!window->parent()) Fl::handle(FL_LEAVE, window);
 
649
    break;
 
650
 
 
651
  case WM_SETFOCUS:
 
652
    Fl::handle(FL_FOCUS, window);
 
653
    break;
 
654
 
 
655
  case WM_KILLFOCUS:
 
656
    Fl::handle(FL_UNFOCUS, window);
 
657
    Fl::flush(); // it never returns to main loop when deactivated...
 
658
    break;
 
659
 
 
660
  case WM_SHOWWINDOW:
 
661
    if (!window->parent()) {
 
662
      Fl::handle(wParam ? FL_SHOW : FL_HIDE, window);
 
663
    }
 
664
    break;
 
665
 
 
666
  case WM_ACTIVATEAPP:
 
667
    // From eric@vfx.sel.sony.com, we should process WM_ACTIVATEAPP
 
668
    // messages to restore the correct state of the shift/ctrl/alt/lock
 
669
    // keys...  Added control, shift, alt, and meta keys, and changed
 
670
    // to use GetAsyncKeyState and do it when wParam is 1
 
671
    // (that means we have focus...)
 
672
    if (wParam)
 
673
    {
 
674
      ulong state = 0;
 
675
      if (GetAsyncKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK;
 
676
      if (GetAsyncKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK;
 
677
      if (GetAsyncKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
 
678
      if (GetAsyncKeyState(VK_CONTROL)&~1) state |= FL_CTRL;
 
679
      if (GetAsyncKeyState(VK_SHIFT)&~1) state |= FL_SHIFT;
 
680
      if (GetAsyncKeyState(VK_MENU)) state |= FL_ALT;
 
681
      if ((GetAsyncKeyState(VK_LWIN)|GetAsyncKeyState(VK_RWIN))&~1) state |= FL_META;
 
682
      Fl::e_state = state;
 
683
      return 0;
 
684
    }
 
685
    break;
 
686
 
 
687
  case WM_KEYDOWN:
 
688
  case WM_SYSKEYDOWN:
 
689
  case WM_KEYUP:
 
690
  case WM_SYSKEYUP:
 
691
    // save the keysym until we figure out the characters:
 
692
    Fl::e_keysym = ms2fltk(wParam,lParam&(1<<24));
 
693
    // See if TranslateMessage turned it into a WM_*CHAR message:
 
694
    if (PeekMessage(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
 
695
      uMsg = fl_msg.message;
 
696
      wParam = fl_msg.wParam;
 
697
      lParam = fl_msg.lParam;
 
698
    }
 
699
  case WM_DEADCHAR:
 
700
  case WM_SYSDEADCHAR:
 
701
  case WM_CHAR:
 
702
  case WM_SYSCHAR: {
 
703
    ulong state = Fl::e_state & 0xff000000; // keep the mouse button state
 
704
    // if GetKeyState is expensive we might want to comment some of these out:
 
705
    if (GetKeyState(VK_SHIFT)&~1) state |= FL_SHIFT;
 
706
    if (GetKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK;
 
707
    if (GetKeyState(VK_CONTROL)&~1) state |= FL_CTRL;
 
708
    // Alt gets reported for the Alt-GR switch on foreign keyboards.
 
709
    // so we need to check the event as well to get it right:
 
710
    if ((lParam&(1<<29)) //same as GetKeyState(VK_MENU)
 
711
        && uMsg != WM_CHAR) state |= FL_ALT;
 
712
    if (GetKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK;
 
713
    if ((GetKeyState(VK_LWIN)|GetKeyState(VK_RWIN))&~1) {
 
714
      // WIN32 bug?  GetKeyState returns garbage if the user hit the
 
715
      // meta key to pop up start menu.  Sigh.
 
716
      if ((GetAsyncKeyState(VK_LWIN)|GetAsyncKeyState(VK_RWIN))&~1)
 
717
        state |= FL_META;
 
718
    }
 
719
    if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
 
720
    Fl::e_state = state;
 
721
    if (lParam & (1<<31)) { // key up events.
 
722
      if (Fl::handle(FL_KEYUP, window)) return 0;
 
723
      break;
 
724
    }
 
725
    static char buffer[2];
 
726
    if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
 
727
      buffer[0] = char(wParam);
 
728
      Fl::e_length = 1;
 
729
    } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
 
730
      buffer[0] = Fl::e_keysym-FL_KP;
 
731
      Fl::e_length = 1;
 
732
    } else {
 
733
      buffer[0] = 0;
 
734
      Fl::e_length = 0;
 
735
    }
 
736
    Fl::e_text = buffer;
 
737
    // for (int i = lParam&0xff; i--;)
 
738
    while (window->parent()) window = window->window();
 
739
    if (Fl::handle(FL_KEYBOARD,window)) return 0;
 
740
    break;}
 
741
 
 
742
  case WM_MOUSEWHEEL: {
 
743
    static int delta = 0; // running total of all motion
 
744
    delta += (SHORT)(HIWORD(wParam));
 
745
    Fl::e_dy = -delta / WHEEL_DELTA;
 
746
    delta += Fl::e_dy * WHEEL_DELTA;
 
747
    if (Fl::e_dy) Fl::handle(FL_MOUSEWHEEL, window);
 
748
    return 0;
 
749
  }
 
750
 
 
751
  case WM_GETMINMAXINFO:
 
752
    Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam);
 
753
    break;
 
754
 
 
755
  case WM_SIZE:
 
756
    if (!window->parent()) {
 
757
      if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) {
 
758
        Fl::handle(FL_HIDE, window);
 
759
      } else {
 
760
        Fl::handle(FL_SHOW, window);
 
761
        resize_bug_fix = window;
 
762
        window->size(LOWORD(lParam), HIWORD(lParam));
 
763
      }
 
764
    }
 
765
    break;
 
766
 
 
767
  case WM_MOVE:
 
768
    resize_bug_fix = window;
 
769
    window->position(LOWORD(lParam), HIWORD(lParam));
 
770
    break;
 
771
 
 
772
  case WM_SETCURSOR:
 
773
    if (LOWORD(lParam) == HTCLIENT) {
 
774
      while (window->parent()) window = window->window();
 
775
      SetCursor(Fl_X::i(window)->cursor);
 
776
      return 0;
 
777
    }
 
778
    break;
 
779
 
 
780
#if USE_COLORMAP
 
781
  case WM_QUERYNEWPALETTE :
 
782
    fl_GetDC(hWnd);
 
783
    if (fl_select_palette()) InvalidateRect(hWnd, NULL, FALSE);
 
784
    break;
 
785
 
 
786
  case WM_PALETTECHANGED:
 
787
    fl_GetDC(hWnd);
 
788
    if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_gc);
 
789
    break;
 
790
 
 
791
  case WM_CREATE :
 
792
    fl_GetDC(hWnd);
 
793
    fl_select_palette();
 
794
    break;
 
795
#endif
 
796
 
 
797
  case WM_DESTROYCLIPBOARD:
 
798
    fl_i_own_selection[1] = 0;
 
799
    return 1;
 
800
 
 
801
  case WM_RENDERALLFORMATS:
 
802
    fl_i_own_selection[1] = 0;
 
803
    // Windoze seems unhappy unless I do these two steps. Documentation
 
804
    // seems to vary on whether opening the clipboard is necessary or
 
805
    // is in fact wrong:
 
806
    CloseClipboard();
 
807
    OpenClipboard(NULL);
 
808
    // fall through...
 
809
  case WM_RENDERFORMAT: {
 
810
    HANDLE h = GlobalAlloc(GHND, fl_selection_length[1]+1);
 
811
    if (h) {
 
812
      LPSTR p = (LPSTR)GlobalLock(h);
 
813
      memcpy(p, fl_selection_buffer[1], fl_selection_length[1]);
 
814
      p[fl_selection_length[1]] = 0;
 
815
      GlobalUnlock(h);
 
816
      SetClipboardData(CF_TEXT, h);
 
817
    }
 
818
    // Windoze also seems unhappy if I don't do this. Documentation very
 
819
    // unclear on what is correct:
 
820
    if (fl_msg.message == WM_RENDERALLFORMATS) CloseClipboard();
 
821
    return 1;}
 
822
 
 
823
  default:
 
824
    if (Fl::handle(0,0)) return 0;
 
825
    break;
 
826
  }
 
827
 
 
828
  return DefWindowProc(hWnd, uMsg, wParam, lParam);
 
829
}
 
830
 
 
831
////////////////////////////////////////////////////////////////
 
832
// This function gets the dimensions of the top/left borders and
 
833
// the title bar, if there is one, based on the FL_BORDER, FL_MODAL
 
834
// and FL_NONMODAL flags, and on the window's size range.
 
835
// It returns the following values:
 
836
//
 
837
// value | border | title bar
 
838
//   0   |  none  |   no
 
839
//   1   |  fix   |   yes
 
840
//   2   |  size  |   yes
 
841
 
 
842
int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by) {
 
843
  int W, H, xoff, yoff, dx, dy;
 
844
  int ret = bx = by = bt = 0;
 
845
  if (w->border() && !w->parent()) {
 
846
    if (w->size_range_set && (w->maxw != w->minw || w->maxh != w->minh)) {
 
847
      ret = 2;
 
848
      bx = GetSystemMetrics(SM_CXSIZEFRAME);
 
849
      by = GetSystemMetrics(SM_CYSIZEFRAME);
 
850
    } else {
 
851
      ret = 1;
 
852
      bx = GetSystemMetrics(SM_CXFIXEDFRAME);
 
853
      by = GetSystemMetrics(SM_CYFIXEDFRAME);
 
854
    }
 
855
    bt = GetSystemMetrics(SM_CYCAPTION);
 
856
  }
 
857
  //The coordinates of the whole window, including non-client area
 
858
  xoff = bx;
 
859
  yoff = by + bt;
 
860
  dx = 2*bx;
 
861
  dy = 2*by + bt;
 
862
  X = w->x()-xoff;
 
863
  Y = w->y()-yoff;
 
864
  W = w->w()+dx;
 
865
  H = w->h()+dy;
 
866
 
 
867
  //Proceed to positioning the window fully inside the screen, if possible
 
868
  //Make border's lower right corner visible
 
869
  if (Fl::w() < X+W) X = Fl::w() - W;
 
870
  if (Fl::h() < Y+H) Y = Fl::h() - H;
 
871
  //Make border's upper left corner visible
 
872
  if (X<0) X = 0;
 
873
  if (Y<0) Y = 0;
 
874
  //Make client area's lower right corner visible
 
875
  if (Fl::w() < X+dx+ w->w()) X = Fl::w() - w->w() - dx;
 
876
  if (Fl::h() < Y+dy+ w->h()) Y = Fl::h() - w->h() - dy;
 
877
  //Make client area's upper left corner visible
 
878
  if (X+xoff < 0) X = -xoff;
 
879
  if (Y+yoff < 0) Y = -yoff;
 
880
  //Return the client area's top left corner in (X,Y)
 
881
  X+=xoff;
 
882
  Y+=yoff;
 
883
 
 
884
  return ret;
 
885
}
 
886
 
 
887
////////////////////////////////////////////////////////////////
 
888
 
 
889
void Fl_Window::resize(int X,int Y,int W,int H) {
 
890
  UINT flags = SWP_NOSENDCHANGING | SWP_NOZORDER;
 
891
  int is_a_resize = (W != w() || H != h());
 
892
  int resize_from_program = (this != resize_bug_fix);
 
893
  if (!resize_from_program) resize_bug_fix = 0;
 
894
  if (X != x() || Y != y()) {
 
895
    set_flag(FL_FORCE_POSITION);
 
896
  } else {
 
897
    if (!is_a_resize) return;
 
898
    flags |= SWP_NOMOVE;
 
899
  }
 
900
  if (is_a_resize) {
 
901
    Fl_Group::resize(X,Y,W,H);
 
902
    if (shown()) {redraw(); i->wait_for_expose = 1;}
 
903
  } else {
 
904
    x(X); y(Y);
 
905
    flags |= SWP_NOSIZE;
 
906
  }
 
907
  if (!border()) flags |= SWP_NOACTIVATE;
 
908
  if (resize_from_program && shown()) {
 
909
    if (!resizable()) size_range(w(),h(),w(),h());
 
910
    int dummy, bt, bx, by;
 
911
    //Ignore window managing when resizing, so that windows (and more
 
912
    //specifically menus) can be moved offscreen.
 
913
    if (Fl_X::fake_X_wm(this, dummy, dummy, bt, bx, by)) {
 
914
      X -= bx;
 
915
      Y -= by+bt;
 
916
      W += 2*bx;
 
917
      H += 2*by+bt;
 
918
    }
 
919
    SetWindowPos(i->xid, 0, X, Y, W, H, flags);
 
920
  }
 
921
}
 
922
 
 
923
////////////////////////////////////////////////////////////////
 
924
 
 
925
void fl_fix_focus(); // in Fl.cxx
 
926
 
 
927
char fl_show_iconic;    // hack for Fl_Window::iconic()
 
928
// int fl_background_pixel = -1; // color to use for background
 
929
HCURSOR fl_default_cursor;
 
930
UINT fl_wake_msg = 0;
 
931
int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
 
932
 
 
933
Fl_X* Fl_X::make(Fl_Window* w) {
 
934
  Fl_Group::current(0); // get rid of very common user bug: forgot end()
 
935
 
 
936
  const char* class_name = /*w->xclass();
 
937
  if (!class_name) class_name =*/ "FLTK"; // create a "FLTK" WNDCLASS
 
938
 
 
939
  const char* message_name = "FLTK::ThreadWakeup";
 
940
 
 
941
  WNDCLASSEX wc;
 
942
  // Documentation states a device context consumes about 800 bytes
 
943
  // of memory... so who cares? If 800 bytes per window is what it
 
944
  // takes to speed things up, I'm game.
 
945
  //wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS;
 
946
  wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
 
947
  wc.lpfnWndProc = (WNDPROC)WndProc;
 
948
  wc.cbClsExtra = wc.cbWndExtra = 0;
 
949
  wc.hInstance = fl_display;
 
950
  if (!w->icon())
 
951
    w->icon((void *)LoadIcon(NULL, IDI_APPLICATION));
 
952
  wc.hIcon = wc.hIconSm = (HICON)w->icon();
 
953
  wc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW);
 
954
  //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b);
 
955
  //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b));
 
956
  wc.hbrBackground = NULL;
 
957
  wc.lpszMenuName = NULL;
 
958
  wc.lpszClassName = class_name;
 
959
  wc.cbSize = sizeof(WNDCLASSEX);
 
960
  RegisterClassEx(&wc);
 
961
  if (!fl_wake_msg) fl_wake_msg = RegisterWindowMessage(message_name);
 
962
 
 
963
  HWND parent;
 
964
  DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
 
965
  DWORD styleEx = WS_EX_LEFT;
 
966
 
 
967
  int xp = w->x();
 
968
  int yp = w->y();
 
969
  int wp = w->w();
 
970
  int hp = w->h();
 
971
 
 
972
  int showit = 1;
 
973
 
 
974
  if (w->parent()) {
 
975
    style |= WS_CHILD;
 
976
    styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
 
977
    parent = fl_xid(w->window());
 
978
  } else {
 
979
    if (!w->size_range_set) {
 
980
      if (w->resizable()) {
 
981
        Fl_Widget *o = w->resizable();
 
982
        int minw = o->w(); if (minw > 100) minw = 100;
 
983
        int minh = o->h(); if (minh > 100) minh = 100;
 
984
        w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0);
 
985
      } else {
 
986
        w->size_range(w->w(), w->h(), w->w(), w->h());
 
987
      }
 
988
    }
 
989
    styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
 
990
    int xwm = xp , ywm = yp , bt, bx, by;
 
991
    switch (fake_X_wm(w, xwm, ywm, bt, bx, by)) {
 
992
      // No border (used for menus)
 
993
      case 0: style |= WS_POPUP;
 
994
              styleEx |= WS_EX_TOOLWINDOW;
 
995
              break;
 
996
 
 
997
      // Thin border and title bar
 
998
      case 1: style |= WS_DLGFRAME | WS_CAPTION; break;
 
999
 
 
1000
      // Thick, resizable border and title bar, with maximize button
 
1001
      case 2: style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_CAPTION ; break;
 
1002
    }
 
1003
    if (by+bt) {
 
1004
      if (!w->modal()) style |= WS_SYSMENU | WS_MINIMIZEBOX;
 
1005
      wp += 2*bx;
 
1006
      hp += 2*by+bt;
 
1007
    }
 
1008
    if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) {
 
1009
      xp = yp = CW_USEDEFAULT;
 
1010
    } else {
 
1011
      if (!Fl::grab()) {
 
1012
        xp = xwm; yp = ywm;
 
1013
        w->x(xp);w->y(yp);
 
1014
      }
 
1015
      xp -= bx;
 
1016
      yp -= by+bt;
 
1017
    }
 
1018
 
 
1019
    parent = 0;
 
1020
    if (w->non_modal() && Fl_X::first && !fl_disable_transient_for) {
 
1021
      // find some other window to be "transient for":
 
1022
      Fl_Window* w = Fl_X::first->w;
 
1023
      while (w->parent()) w = w->window();
 
1024
      parent = fl_xid(w);
 
1025
      if (!w->visible()) showit = 0;
 
1026
    } else if (Fl::grab()) parent = fl_xid(Fl::grab());
 
1027
  }
 
1028
 
 
1029
  Fl_X* x = new Fl_X;
 
1030
  x->other_xid = 0;
 
1031
  x->setwindow(w);
 
1032
  x->region = 0;
 
1033
  x->private_dc = 0;
 
1034
  x->cursor = fl_default_cursor;
 
1035
  x->xid = CreateWindowEx(
 
1036
    styleEx,
 
1037
    class_name, w->label(), style,
 
1038
    xp, yp, wp, hp,
 
1039
    parent,
 
1040
    NULL, // menu
 
1041
    fl_display,
 
1042
    NULL // creation parameters
 
1043
    );
 
1044
  x->next = Fl_X::first;
 
1045
  Fl_X::first = x;
 
1046
 
 
1047
  x->wait_for_expose = 1;
 
1048
  if (fl_show_iconic) {showit = 0; fl_show_iconic = 0;}
 
1049
  if (showit) {
 
1050
    w->set_visible();
 
1051
    w->handle(FL_SHOW); // get child windows to appear
 
1052
    w->redraw(); // force draw to happen
 
1053
  }
 
1054
  // If we've captured the mouse, we dont want do activate any
 
1055
  // other windows from the code, or we loose the capture.
 
1056
  ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE :
 
1057
             (Fl::grab() || (style & WS_POPUP)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL);
 
1058
 
 
1059
  // Drag-n-drop requires GCC 3.x or a non-GNU compiler...
 
1060
#if !defined(__GNUC__) || __GNUC__ >= 3
 
1061
  // Register all windows for potential drag'n'drop operations
 
1062
  static char oleInitialized = 0;
 
1063
  if (!oleInitialized) { OleInitialize(0L); oleInitialized=1; }
 
1064
 
 
1065
  RegisterDragDrop(x->xid, flIDropTarget);
 
1066
#endif // !__GNUC__ || __GNUC__ >= 3
 
1067
 
 
1068
  if (w->modal()) {Fl::modal_ = w; fl_fix_focus();}
 
1069
  return x;
 
1070
}
 
1071
 
 
1072
////////////////////////////////////////////////////////////////
 
1073
 
 
1074
HINSTANCE fl_display = GetModuleHandle(NULL);
 
1075
 
 
1076
void Fl_Window::size_range_() {
 
1077
  size_range_set = 1;
 
1078
}
 
1079
 
 
1080
void Fl_X::set_minmax(LPMINMAXINFO minmax)
 
1081
{
 
1082
  int td, wd, hd, dummy;
 
1083
 
 
1084
  fake_X_wm(w, dummy, dummy, td, wd, hd);
 
1085
  wd *= 2;
 
1086
  hd *= 2;
 
1087
  hd += td;
 
1088
 
 
1089
  minmax->ptMinTrackSize.x = w->minw + wd;
 
1090
  minmax->ptMinTrackSize.y = w->minh + hd;
 
1091
  if (w->maxw) {
 
1092
    minmax->ptMaxTrackSize.x = w->maxw + wd;
 
1093
    minmax->ptMaxSize.x = w->maxw + wd;
 
1094
  }
 
1095
  if (w->maxh) {
 
1096
    minmax->ptMaxTrackSize.y = w->maxh + hd;
 
1097
    minmax->ptMaxSize.y = w->maxh + hd;
 
1098
  }
 
1099
}
 
1100
 
 
1101
////////////////////////////////////////////////////////////////
 
1102
 
 
1103
#include <FL/filename.H> // need so FL_EXPORT fl_filename_name works
 
1104
 
 
1105
// returns pointer to the filename, or null if name ends with '/'
 
1106
const char *fl_filename_name(const char *name) {
 
1107
  const char *p,*q;
 
1108
  if (!name) return (0);
 
1109
  q = name;
 
1110
  if (q[0] && q[1]==':') q += 2; // skip leading drive letter
 
1111
  for (p = q; *p; p++) if (*p == '/' || *p == '\\') q = p+1;
 
1112
  return q;
 
1113
}
 
1114
 
 
1115
void Fl_Window::label(const char *name,const char *iname) {
 
1116
  Fl_Widget::label(name);
 
1117
  iconlabel_ = iname;
 
1118
  if (shown() && !parent()) {
 
1119
    if (!name) name = "";
 
1120
    SetWindowText(i->xid, name);
 
1121
    // if (!iname) iname = fl_filename_name(name);
 
1122
    // should do something with iname here...
 
1123
  }
 
1124
}
 
1125
 
 
1126
////////////////////////////////////////////////////////////////
 
1127
// Implement the virtual functions for the base Fl_Window class:
 
1128
 
 
1129
// If the box is a filled rectangle, we can make the redisplay *look*
 
1130
// faster by using X's background pixel erasing.  We can make it
 
1131
// actually *be* faster by drawing the frame only, this is done by
 
1132
// setting fl_boxcheat, which is seen by code in fl_drawbox.cxx:
 
1133
// For WIN32 it looks like all windows share a background color, so
 
1134
// I use FL_GRAY for this and only do this cheat for windows that are
 
1135
// that color.
 
1136
// Actually it is totally disabled.
 
1137
// Fl_Widget *fl_boxcheat;
 
1138
//static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);}
 
1139
 
 
1140
void Fl_Window::show() {
 
1141
  image(Fl::scheme_bg_);
 
1142
  if (Fl::scheme_bg_) {
 
1143
    labeltype(FL_NORMAL_LABEL);
 
1144
    align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP);
 
1145
  } else {
 
1146
    labeltype(FL_NO_LABEL);
 
1147
  }
 
1148
  if (!shown()) {
 
1149
    // if (can_boxcheat(box())) fl_background_pixel = fl_xpixel(color());
 
1150
    Fl_X::make(this);
 
1151
  } else {
 
1152
    // Once again, we would lose the capture if we activated the window.
 
1153
    if (IsIconic(i->xid)) OpenIcon(i->xid);
 
1154
    if (!fl_capture) BringWindowToTop(i->xid);
 
1155
    //ShowWindow(i->xid,fl_capture?SW_SHOWNOACTIVATE:SW_RESTORE);
 
1156
  }
 
1157
}
 
1158
 
 
1159
Fl_Window *Fl_Window::current_;
 
1160
// the current context
 
1161
HDC fl_gc = 0;
 
1162
// the current window handle, initially set to -1 so we can correctly
 
1163
// allocate fl_GetDC(0)
 
1164
HWND fl_window = (HWND)-1;
 
1165
 
 
1166
// Here we ensure only one GetDC is ever in place.
 
1167
HDC fl_GetDC(HWND w) {
 
1168
  if (fl_gc) {
 
1169
    if (w == fl_window) return fl_gc;
 
1170
    ReleaseDC(fl_window, fl_gc);
 
1171
  }
 
1172
  fl_gc = GetDC(w);
 
1173
  fl_window = w;
 
1174
  // calling GetDC seems to always reset these: (?)
 
1175
  SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT);
 
1176
  SetBkMode(fl_gc, TRANSPARENT);
 
1177
  return fl_gc;
 
1178
}
 
1179
 
 
1180
// make X drawing go into this window (called by subclass flush() impl.)
 
1181
void Fl_Window::make_current() {
 
1182
  fl_GetDC(fl_xid(this));
 
1183
 
 
1184
#if USE_COLORMAP
 
1185
  // Windows maintains a hardware and software color palette; the
 
1186
  // SelectPalette() call updates the current soft->hard mapping
 
1187
  // for all drawing calls, so we must select it here before any
 
1188
  // code does any drawing...
 
1189
 
 
1190
  fl_select_palette();
 
1191
#endif // USE_COLORMAP
 
1192
 
 
1193
  current_ = this;
 
1194
  fl_clip_region(0);
 
1195
}
 
1196
 
 
1197
//
 
1198
// End of "$Id: Fl_win32.cxx,v 1.33.2.37.2.48 2004/04/11 04:38:59 easysw Exp $".
 
1199
//