w32xfns.c 8.25 KB
Newer Older
1
/* Functions taken directly from X sources for use with the Microsoft Windows API.
Paul Eggert's avatar
Paul Eggert committed
2
   Copyright (C) 1989, 1992-1995, 1999, 2001-2020 Free Software
3
   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
Paul Eggert's avatar
Paul Eggert committed
18
along with GNU Emacs.  If not, see <https://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>
23 24
#include <windows.h>
#include <windowsx.h>
Daniel Colascione's avatar
Daniel Colascione committed
25

Geoff Voelker's avatar
Geoff Voelker committed
26
#include "lisp.h"
Geoff Voelker's avatar
Geoff Voelker committed
27
#include "frame.h"
Geoff Voelker's avatar
Geoff Voelker committed
28 29 30 31 32
#include "w32term.h"

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

Geoff Voelker's avatar
Geoff Voelker committed
33
CRITICAL_SECTION critsect;
Daniel Colascione's avatar
Daniel Colascione committed
34 35

#ifdef WINDOWSNT
Geoff Voelker's avatar
Geoff Voelker committed
36
extern HANDLE keyboard_handle;
Daniel Colascione's avatar
Daniel Colascione committed
37 38
#endif /* WINDOWSNT */

Geoff Voelker's avatar
Geoff Voelker committed
39
HANDLE input_available = NULL;
40
HANDLE interrupt_handle = NULL;
Geoff Voelker's avatar
Geoff Voelker committed
41

42
void
43
init_crit (void)
Geoff Voelker's avatar
Geoff Voelker committed
44
{
Geoff Voelker's avatar
Geoff Voelker committed
45
  InitializeCriticalSection (&critsect);
Geoff Voelker's avatar
Geoff Voelker committed
46

Geoff Voelker's avatar
Geoff Voelker committed
47 48
  /* 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
49 50
  input_available = CreateEvent (NULL, TRUE, FALSE, NULL);

51
#if HAVE_W32NOTIFY
52 53 54 55 56 57 58 59 60 61 62 63
  /* Initialize the linked list of notifications sets that will be
     used to communicate between the watching worker threads and the
     main thread.  */
  notifications_set_head = malloc (sizeof(struct notifications_set));
  if (notifications_set_head)
    {
      memset (notifications_set_head, 0, sizeof(struct notifications_set));
      notifications_set_head->next
	= notifications_set_head->prev = notifications_set_head;
    }
  else
    DebPrint(("Out of memory: can't initialize notifications sets."));
64
#endif
65

Daniel Colascione's avatar
Daniel Colascione committed
66 67 68
#ifdef WINDOWSNT
  keyboard_handle = input_available;
#endif /* WINDOWSNT */
69

Glenn Morris's avatar
Glenn Morris committed
70
  /* interrupt_handle is signaled when quit (C-g) is detected, so that
71 72 73 74
     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
75
     signal this event, so that it never remains signaled.  */
76
  interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
Geoff Voelker's avatar
Geoff Voelker committed
77 78
}

79
void
80
delete_crit (void)
Geoff Voelker's avatar
Geoff Voelker committed
81
{
Geoff Voelker's avatar
Geoff Voelker committed
82 83 84 85 86 87 88
  DeleteCriticalSection (&critsect);

  if (input_available)
    {
      CloseHandle (input_available);
      input_available = NULL;
    }
89 90 91 92 93
  if (interrupt_handle)
    {
      CloseHandle (interrupt_handle);
      interrupt_handle = NULL;
    }
94

95
#if HAVE_W32NOTIFY
96 97 98 99 100 101 102 103 104 105 106 107 108 109
  if (notifications_set_head)
    {
      /* Free any remaining notifications set that could be left over.  */
      while (notifications_set_head->next != notifications_set_head)
	{
	  struct notifications_set *ns = notifications_set_head->next;
	  notifications_set_head->next = ns->next;
	  ns->next->prev = notifications_set_head;
	  if (ns->notifications)
	    free (ns->notifications);
	  free (ns);
	}
    }
  free (notifications_set_head);
110
#endif
111 112 113
}

void
114
signal_quit (void)
115
{
Glenn Morris's avatar
Glenn Morris committed
116
  /* Make sure this event never remains signaled; if the main thread
117 118
     isn't in a blocking call, then this should do nothing.  */
  PulseEvent (interrupt_handle);
Geoff Voelker's avatar
Geoff Voelker committed
119 120
}

Geoff Voelker's avatar
Geoff Voelker committed
121
void
Dmitry Antipov's avatar
Dmitry Antipov committed
122
select_palette (struct frame *f, HDC hdc)
Geoff Voelker's avatar
Geoff Voelker committed
123
{
124
  struct w32_display_info *display_info = FRAME_DISPLAY_INFO (f);
125 126 127 128 129

  if (!display_info->has_palette)
    return;

  if (display_info->palette == 0)
130
    return;
131

132 133
  if (!NILP (Vw32_enable_palette))
    f->output_data.w32->old_palette =
134
      SelectPalette (hdc, display_info->palette, FALSE);
Geoff Voelker's avatar
Geoff Voelker committed
135
  else
136
    f->output_data.w32->old_palette = NULL;
Geoff Voelker's avatar
Geoff Voelker committed
137

138
  if (RealizePalette (hdc) != GDI_ERROR)
Geoff Voelker's avatar
Geoff Voelker committed
139 140 141
  {
    Lisp_Object frame, framelist;
    FOR_EACH_FRAME (framelist, frame)
Geoff Voelker's avatar
Geoff Voelker committed
142
    {
Geoff Voelker's avatar
Geoff Voelker committed
143
      SET_FRAME_GARBAGED (XFRAME (frame));
Geoff Voelker's avatar
Geoff Voelker committed
144
    }
Geoff Voelker's avatar
Geoff Voelker committed
145 146 147 148
  }
}

void
Dmitry Antipov's avatar
Dmitry Antipov committed
149
deselect_palette (struct frame *f, HDC hdc)
Geoff Voelker's avatar
Geoff Voelker committed
150
{
151 152
  if (f->output_data.w32->old_palette)
    SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
Geoff Voelker's avatar
Geoff Voelker committed
153 154 155 156 157
}

/* 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
158
get_frame_dc (struct frame *f)
Geoff Voelker's avatar
Geoff Voelker committed
159 160 161
{
  HDC hdc;

162
  if (f->output_method != output_w32)
163
    emacs_abort ();
164

Geoff Voelker's avatar
Geoff Voelker committed
165 166
  enter_crit ();

167
  hdc = GetDC (f->output_data.w32->window_desc);
168 169 170 171 172

  /* 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
173 174 175 176 177

  return hdc;
}

int
Dmitry Antipov's avatar
Dmitry Antipov committed
178
release_frame_dc (struct frame *f, HDC hdc)
Geoff Voelker's avatar
Geoff Voelker committed
179 180 181 182
{
  int ret;

  deselect_palette (f, hdc);
183
  ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
Geoff Voelker's avatar
Geoff Voelker committed
184 185 186 187

  leave_crit ();

  return ret;
Geoff Voelker's avatar
Geoff Voelker committed
188 189 190 191
}

typedef struct int_msg
{
192
  W32Msg w32msg;
Geoff Voelker's avatar
Geoff Voelker committed
193 194 195 196 197 198 199
  struct int_msg *lpNext;
} int_msg;

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

200
BOOL
201
get_next_msg (W32Msg * lpmsg, BOOL bWait)
Geoff Voelker's avatar
Geoff Voelker committed
202 203
{
  BOOL bRet = FALSE;
204

Geoff Voelker's avatar
Geoff Voelker committed
205
  enter_crit ();
206

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

Geoff Voelker's avatar
Geoff Voelker committed
209 210
  while (!nQueue && bWait)
    {
Geoff Voelker's avatar
Geoff Voelker committed
211
      leave_crit ();
Geoff Voelker's avatar
Geoff Voelker committed
212
      WaitForSingleObject (input_available, INFINITE);
Geoff Voelker's avatar
Geoff Voelker committed
213
      enter_crit ();
Geoff Voelker's avatar
Geoff Voelker committed
214
    }
215

Geoff Voelker's avatar
Geoff Voelker committed
216 217
  if (nQueue)
    {
218
      memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
Geoff Voelker's avatar
Geoff Voelker committed
219 220 221

      {
	int_msg * lpCur = lpHead;
222

Geoff Voelker's avatar
Geoff Voelker committed
223
	lpHead = lpHead->lpNext;
224

Geoff Voelker's avatar
Geoff Voelker committed
225 226 227 228
	myfree (lpCur);
      }

      nQueue--;
Paul Eggert's avatar
Paul Eggert committed
229
      /* Consolidate WM_PAINT messages to optimize redrawing.  */
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
      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)))
                    {
254
                      SetRectEmpty (&(lpmsg->rect));
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
                    }

                  myfree (lpCur);

                  nQueue--;

                  lpCur = lpNext;
                }
              else
                {
                  lpPrev = lpCur;
                  lpCur = lpNext;
                }
            }
        }
Geoff Voelker's avatar
Geoff Voelker committed
270 271 272

      bRet = TRUE;
    }
Geoff Voelker's avatar
Geoff Voelker committed
273 274 275

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

Geoff Voelker's avatar
Geoff Voelker committed
277
  leave_crit ();
278

Geoff Voelker's avatar
Geoff Voelker committed
279 280 281
  return (bRet);
}

Daniel Colascione's avatar
Daniel Colascione committed
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
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 */
}

298
BOOL
299
post_msg (W32Msg * lpmsg)
Geoff Voelker's avatar
Geoff Voelker committed
300 301 302
{
  int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));

Geoff Voelker's avatar
Geoff Voelker committed
303 304
  if (!lpNew)
    return (FALSE);
Geoff Voelker's avatar
Geoff Voelker committed
305

306
  memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
Geoff Voelker's avatar
Geoff Voelker committed
307 308
  lpNew->lpNext = NULL;

Geoff Voelker's avatar
Geoff Voelker committed
309
  enter_crit ();
Geoff Voelker's avatar
Geoff Voelker committed
310 311

  if (nQueue++)
Geoff Voelker's avatar
Geoff Voelker committed
312 313 314
    {
      lpTail->lpNext = lpNew;
    }
315
  else
Geoff Voelker's avatar
Geoff Voelker committed
316 317 318
    {
      lpHead = lpNew;
    }
Geoff Voelker's avatar
Geoff Voelker committed
319 320

  lpTail = lpNew;
Daniel Colascione's avatar
Daniel Colascione committed
321
  notify_msg_ready ();
Geoff Voelker's avatar
Geoff Voelker committed
322
  leave_crit ();
Geoff Voelker's avatar
Geoff Voelker committed
323 324 325 326

  return (TRUE);
}

Geoff Voelker's avatar
Geoff Voelker committed
327
BOOL
328
prepend_msg (W32Msg *lpmsg)
Geoff Voelker's avatar
Geoff Voelker committed
329 330 331 332 333 334
{
  int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));

  if (!lpNew)
    return (FALSE);

335
  memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
Geoff Voelker's avatar
Geoff Voelker committed
336 337 338 339 340 341

  enter_crit ();

  nQueue++;
  lpNew->lpNext = lpHead;
  lpHead = lpNew;
Daniel Colascione's avatar
Daniel Colascione committed
342
  notify_msg_ready ();
Geoff Voelker's avatar
Geoff Voelker committed
343 344 345 346 347
  leave_crit ();

  return (TRUE);
}

348 349 350
/* Process all messages in the current thread's queue.  Value is 1 if
   one of these messages was WM_EMACS_FILENOTIFY, zero otherwise.  */
int
351
drain_message_queue (void)
352 353
{
  MSG msg;
354 355
  int retval = 0;

356 357
  while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
    {
358 359
      if (msg.message == WM_EMACS_FILENOTIFY)
	retval = 1;
360 361 362
      TranslateMessage (&msg);
      DispatchMessage (&msg);
    }
363
  return retval;
364
}