w32xfns.c 7.34 KB
Newer Older
1
/* Functions taken directly from X sources for use with the Microsoft Windows API.
2 3
   Copyright (C) 1989, 1992-1995, 1999, 2001-2013 Free Software
   Foundation, Inc.
Geoff Voelker's avatar
Geoff Voelker committed
4 5 6

This file is part of GNU Emacs.

7
GNU Emacs is free software: you can redistribute it and/or modify
Geoff Voelker's avatar
Geoff Voelker committed
8
it under the terms of the GNU General Public License as published by
9 10
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Geoff Voelker's avatar
Geoff Voelker committed
11 12 13 14 15 16 17

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
18
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Geoff Voelker's avatar
Geoff Voelker committed
19 20

#include <config.h>
21
#include <signal.h>
Geoff Voelker's avatar
Geoff Voelker committed
22
#include <stdio.h>
Daniel Colascione's avatar
Daniel Colascione committed
23

Geoff Voelker's avatar
Geoff Voelker committed
24
#include "lisp.h"
25
#include "keyboard.h"
Geoff Voelker's avatar
Geoff Voelker committed
26
#include "frame.h"
27
#include "window.h"
28 29
#include "charset.h"
#include "fontset.h"
Geoff Voelker's avatar
Geoff Voelker committed
30 31 32 33 34 35 36
#include "blockinput.h"
#include "w32term.h"
#include "windowsx.h"

#define myalloc(cb) GlobalAllocPtr (GPTR, cb)
#define myfree(lp) GlobalFreePtr (lp)

Geoff Voelker's avatar
Geoff Voelker committed
37
CRITICAL_SECTION critsect;
Daniel Colascione's avatar
Daniel Colascione committed
38 39

#ifdef WINDOWSNT
Geoff Voelker's avatar
Geoff Voelker committed
40
extern HANDLE keyboard_handle;
Daniel Colascione's avatar
Daniel Colascione committed
41 42
#endif /* WINDOWSNT */

Geoff Voelker's avatar
Geoff Voelker committed
43
HANDLE input_available = NULL;
44
HANDLE interrupt_handle = NULL;
Geoff Voelker's avatar
Geoff Voelker committed
45

46
void
47
init_crit (void)
Geoff Voelker's avatar
Geoff Voelker committed
48
{
Geoff Voelker's avatar
Geoff Voelker committed
49
  InitializeCriticalSection (&critsect);
Geoff Voelker's avatar
Geoff Voelker committed
50

Geoff Voelker's avatar
Geoff Voelker committed
51 52
  /* For safety, input_available should only be reset by get_next_msg
     when the input queue is empty, so make it a manual reset event. */
Daniel Colascione's avatar
Daniel Colascione committed
53 54 55 56 57
  input_available = CreateEvent (NULL, TRUE, FALSE, NULL);

#ifdef WINDOWSNT
  keyboard_handle = input_available;
#endif /* WINDOWSNT */
58

Glenn Morris's avatar
Glenn Morris committed
59
  /* interrupt_handle is signaled when quit (C-g) is detected, so that
60 61 62 63
     blocking system calls can be interrupted.  We make it a manual
     reset event, so that if we should ever have multiple threads
     performing system calls, they will all be interrupted (I'm guessing
     that would the right response).  Note that we use PulseEvent to
Glenn Morris's avatar
Glenn Morris committed
64
     signal this event, so that it never remains signaled.  */
65
  interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
Geoff Voelker's avatar
Geoff Voelker committed
66 67
}

68
void
69
delete_crit (void)
Geoff Voelker's avatar
Geoff Voelker committed
70
{
Geoff Voelker's avatar
Geoff Voelker committed
71 72 73 74 75 76 77
  DeleteCriticalSection (&critsect);

  if (input_available)
    {
      CloseHandle (input_available);
      input_available = NULL;
    }
78 79 80 81 82 83 84 85
  if (interrupt_handle)
    {
      CloseHandle (interrupt_handle);
      interrupt_handle = NULL;
    }
}

void
86
signal_quit (void)
87
{
Glenn Morris's avatar
Glenn Morris committed
88
  /* Make sure this event never remains signaled; if the main thread
89 90
     isn't in a blocking call, then this should do nothing.  */
  PulseEvent (interrupt_handle);
Geoff Voelker's avatar
Geoff Voelker committed
91 92
}

Geoff Voelker's avatar
Geoff Voelker committed
93
void
Dmitry Antipov's avatar
Dmitry Antipov committed
94
select_palette (struct frame *f, HDC hdc)
Geoff Voelker's avatar
Geoff Voelker committed
95
{
96
  struct w32_display_info *display_info = FRAME_DISPLAY_INFO (f);
97 98 99 100 101

  if (!display_info->has_palette)
    return;

  if (display_info->palette == 0)
102
    return;
103

104 105
  if (!NILP (Vw32_enable_palette))
    f->output_data.w32->old_palette =
106
      SelectPalette (hdc, display_info->palette, FALSE);
Geoff Voelker's avatar
Geoff Voelker committed
107
  else
108
    f->output_data.w32->old_palette = NULL;
Geoff Voelker's avatar
Geoff Voelker committed
109

110
  if (RealizePalette (hdc) != GDI_ERROR)
Geoff Voelker's avatar
Geoff Voelker committed
111 112 113
  {
    Lisp_Object frame, framelist;
    FOR_EACH_FRAME (framelist, frame)
Geoff Voelker's avatar
Geoff Voelker committed
114
    {
Geoff Voelker's avatar
Geoff Voelker committed
115
      SET_FRAME_GARBAGED (XFRAME (frame));
Geoff Voelker's avatar
Geoff Voelker committed
116
    }
Geoff Voelker's avatar
Geoff Voelker committed
117 118 119 120
  }
}

void
Dmitry Antipov's avatar
Dmitry Antipov committed
121
deselect_palette (struct frame *f, HDC hdc)
Geoff Voelker's avatar
Geoff Voelker committed
122
{
123 124
  if (f->output_data.w32->old_palette)
    SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
Geoff Voelker's avatar
Geoff Voelker committed
125 126 127 128 129
}

/* Get a DC for frame and select palette for drawing; force an update of
   all frames if palette's mapping changes.  */
HDC
Dmitry Antipov's avatar
Dmitry Antipov committed
130
get_frame_dc (struct frame *f)
Geoff Voelker's avatar
Geoff Voelker committed
131 132 133
{
  HDC hdc;

134
  if (f->output_method != output_w32)
135
    emacs_abort ();
136

Geoff Voelker's avatar
Geoff Voelker committed
137 138
  enter_crit ();

139
  hdc = GetDC (f->output_data.w32->window_desc);
140 141 142 143 144

  /* If this gets called during startup before the frame is valid,
     there is a chance of corrupting random data or crashing. */
  if (hdc)
    select_palette (f, hdc);
Geoff Voelker's avatar
Geoff Voelker committed
145 146 147 148 149

  return hdc;
}

int
Dmitry Antipov's avatar
Dmitry Antipov committed
150
release_frame_dc (struct frame *f, HDC hdc)
Geoff Voelker's avatar
Geoff Voelker committed
151 152 153 154
{
  int ret;

  deselect_palette (f, hdc);
155
  ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
Geoff Voelker's avatar
Geoff Voelker committed
156 157 158 159

  leave_crit ();

  return ret;
Geoff Voelker's avatar
Geoff Voelker committed
160 161 162 163
}

typedef struct int_msg
{
164
  W32Msg w32msg;
Geoff Voelker's avatar
Geoff Voelker committed
165 166 167 168 169 170 171
  struct int_msg *lpNext;
} int_msg;

int_msg *lpHead = NULL;
int_msg *lpTail = NULL;
int nQueue = 0;

172
BOOL
173
get_next_msg (W32Msg * lpmsg, BOOL bWait)
Geoff Voelker's avatar
Geoff Voelker committed
174 175
{
  BOOL bRet = FALSE;
176

Geoff Voelker's avatar
Geoff Voelker committed
177
  enter_crit ();
178

Geoff Voelker's avatar
Geoff Voelker committed
179
  /* The while loop takes care of multiple sets */
180

Geoff Voelker's avatar
Geoff Voelker committed
181 182
  while (!nQueue && bWait)
    {
Geoff Voelker's avatar
Geoff Voelker committed
183
      leave_crit ();
Geoff Voelker's avatar
Geoff Voelker committed
184
      WaitForSingleObject (input_available, INFINITE);
Geoff Voelker's avatar
Geoff Voelker committed
185
      enter_crit ();
Geoff Voelker's avatar
Geoff Voelker committed
186
    }
187

Geoff Voelker's avatar
Geoff Voelker committed
188 189
  if (nQueue)
    {
190
      memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
Geoff Voelker's avatar
Geoff Voelker committed
191 192 193

      {
	int_msg * lpCur = lpHead;
194

Geoff Voelker's avatar
Geoff Voelker committed
195
	lpHead = lpHead->lpNext;
196

Geoff Voelker's avatar
Geoff Voelker committed
197 198 199 200
	myfree (lpCur);
      }

      nQueue--;
Paul Eggert's avatar
Paul Eggert committed
201
      /* Consolidate WM_PAINT messages to optimize redrawing.  */
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
      if (lpmsg->msg.message == WM_PAINT && nQueue)
        {
          int_msg * lpCur = lpHead;
          int_msg * lpPrev = NULL;
          int_msg * lpNext = NULL;

          while (lpCur && nQueue)
            {
              lpNext = lpCur->lpNext;
              if (lpCur->w32msg.msg.message == WM_PAINT)
                {
                  /* Remove this message from the queue.  */
                  if (lpPrev)
                    lpPrev->lpNext = lpNext;
                  else
                    lpHead = lpNext;

                  if (lpCur == lpTail)
                    lpTail = lpPrev;

                  /* Adjust clip rectangle to cover both.  */
                  if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
                                  &(lpCur->w32msg.rect)))
                    {
226
                      SetRectEmpty (&(lpmsg->rect));
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
                    }

                  myfree (lpCur);

                  nQueue--;

                  lpCur = lpNext;
                }
              else
                {
                  lpPrev = lpCur;
                  lpCur = lpNext;
                }
            }
        }
Geoff Voelker's avatar
Geoff Voelker committed
242 243 244

      bRet = TRUE;
    }
Geoff Voelker's avatar
Geoff Voelker committed
245 246 247

  if (nQueue == 0)
    ResetEvent (input_available);
248

Geoff Voelker's avatar
Geoff Voelker committed
249
  leave_crit ();
250

Geoff Voelker's avatar
Geoff Voelker committed
251 252 253
  return (bRet);
}

Daniel Colascione's avatar
Daniel Colascione committed
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
extern char * w32_strerror (int error_no);

/* Tell the main thread that we have input available; if the main
   thread is blocked in select(), we wake it up here.  */
static void
notify_msg_ready (void)
{
  SetEvent (input_available);

#ifdef CYGWIN
  /* Wakes up the main thread, which is blocked select()ing for /dev/windows,
     among other files.  */
  (void) PostThreadMessage (dwMainThreadId, WM_EMACS_INPUT_READY, 0, 0);
#endif /* CYGWIN */
}

270
BOOL
271
post_msg (W32Msg * lpmsg)
Geoff Voelker's avatar
Geoff Voelker committed
272 273 274
{
  int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));

Geoff Voelker's avatar
Geoff Voelker committed
275 276
  if (!lpNew)
    return (FALSE);
Geoff Voelker's avatar
Geoff Voelker committed
277

278
  memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
Geoff Voelker's avatar
Geoff Voelker committed
279 280
  lpNew->lpNext = NULL;

Geoff Voelker's avatar
Geoff Voelker committed
281
  enter_crit ();
Geoff Voelker's avatar
Geoff Voelker committed
282 283

  if (nQueue++)
Geoff Voelker's avatar
Geoff Voelker committed
284 285 286
    {
      lpTail->lpNext = lpNew;
    }
287
  else
Geoff Voelker's avatar
Geoff Voelker committed
288 289 290
    {
      lpHead = lpNew;
    }
Geoff Voelker's avatar
Geoff Voelker committed
291 292

  lpTail = lpNew;
Daniel Colascione's avatar
Daniel Colascione committed
293
  notify_msg_ready ();
Geoff Voelker's avatar
Geoff Voelker committed
294
  leave_crit ();
Geoff Voelker's avatar
Geoff Voelker committed
295 296 297 298

  return (TRUE);
}

Geoff Voelker's avatar
Geoff Voelker committed
299
BOOL
300
prepend_msg (W32Msg *lpmsg)
Geoff Voelker's avatar
Geoff Voelker committed
301 302 303 304 305 306
{
  int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));

  if (!lpNew)
    return (FALSE);

307
  memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
Geoff Voelker's avatar
Geoff Voelker committed
308 309 310 311 312 313

  enter_crit ();

  nQueue++;
  lpNew->lpNext = lpHead;
  lpHead = lpNew;
Daniel Colascione's avatar
Daniel Colascione committed
314
  notify_msg_ready ();
Geoff Voelker's avatar
Geoff Voelker committed
315 316 317 318 319
  leave_crit ();

  return (TRUE);
}

320 321 322
/* Process all messages in the current thread's queue.  Value is 1 if
   one of these messages was WM_EMACS_FILENOTIFY, zero otherwise.  */
int
323
drain_message_queue (void)
324 325
{
  MSG msg;
326 327
  int retval = 0;

328 329
  while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
    {
330 331
      if (msg.message == WM_EMACS_FILENOTIFY)
	retval = 1;
332 333 334
      TranslateMessage (&msg);
      DispatchMessage (&msg);
    }
335
  return retval;
336
}